clang-format

This commit is contained in:
Adam Ierymenko 2025-07-03 11:26:23 -04:00
parent d45f280cb7
commit ba2a4a605c
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
140 changed files with 19214 additions and 17403 deletions

View file

@ -31,3 +31,6 @@ drone:
@echo "rendering .drone.yaml from .drone.jsonnet"
drone jsonnet --format --stream
drone sign zerotier/ZeroTierOne --save
clang-format:
find node osdep service tcp-proxy controller -iname '*.cpp' -o -iname '*.hpp' | xargs clang-format -i

File diff suppressed because it is too large Load diff

View file

@ -20,19 +20,16 @@
#define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4
#include "ConnectionPool.hpp"
#include <pqxx/pqxx>
#include <memory>
#include <redis++/redis++.h>
#include "../node/Metrics.hpp"
#include "ConnectionPool.hpp"
#include "PostgreSQL.hpp"
#include <memory>
#include <pqxx/pqxx>
#include <redis++/redis++.h>
namespace smeeclient {
struct SmeeClient;
struct SmeeClient;
}
namespace ZeroTier {
@ -45,39 +42,43 @@ struct RedisConfig;
* This is for use with ZeroTier Central. Others are free to build and use it
* but be aware that we might change it at any time.
*/
class CV1 : public DB
{
public:
CV1(const Identity &myId, const char *path, int listenPort, RedisConfig *rc);
class CV1 : public DB {
public:
CV1(const Identity& myId, const char* path, int listenPort, RedisConfig* rc);
virtual ~CV1();
virtual bool waitForReady();
virtual bool isReady();
virtual bool save(nlohmann::json &record,bool notifyListeners);
virtual bool save(nlohmann::json& record, bool notifyListeners);
virtual void eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch);
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch);
virtual AuthInfo getSSOAuthInfo(const nlohmann::json& member, const std::string& redirectURL);
virtual bool ready() {
virtual bool ready()
{
return _ready == 2;
}
protected:
struct _PairHasher
{
inline std::size_t operator()(const std::pair<uint64_t,uint64_t> &p) const { return (std::size_t)(p.first ^ p.second); }
protected:
struct _PairHasher {
inline std::size_t operator()(const std::pair<uint64_t, uint64_t>& p) const
{
return (std::size_t)(p.first ^ p.second);
}
};
virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners) {
virtual void _memberChanged(nlohmann::json& old, nlohmann::json& memberConfig, bool notifyListeners)
{
DB::_memberChanged(old, memberConfig, notifyListeners);
}
virtual void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners) {
virtual void _networkChanged(nlohmann::json& old, nlohmann::json& networkConfig, bool notifyListeners)
{
DB::_networkChanged(old, networkConfig, notifyListeners);
}
private:
private:
void initializeNetworks();
void initializeMembers();
void heartbeat();
@ -93,16 +94,12 @@ private:
void onlineNotificationThread();
void onlineNotification_Postgres();
void onlineNotification_Redis();
uint64_t _doRedisUpdate(sw::redis::Transaction &tx, std::string &controllerId,
std::unordered_map< std::pair<uint64_t,uint64_t>,NodeOnlineRecord,_PairHasher > &lastOnline);
uint64_t _doRedisUpdate(sw::redis::Transaction& tx, std::string& controllerId, std::unordered_map<std::pair<uint64_t, uint64_t>, NodeOnlineRecord, _PairHasher>& lastOnline);
void configureSmee();
void notifyNewMember(const std::string &networkID, const std::string &memberID);
void notifyNewMember(const std::string& networkID, const std::string& memberID);
enum OverrideMode {
ALLOW_PGBOUNCER_OVERRIDE = 0,
NO_OVERRIDE = 1
};
enum OverrideMode { ALLOW_PGBOUNCER_OVERRIDE = 0, NO_OVERRIDE = 1 };
std::shared_ptr<ConnectionPool<PostgresConnection> > _pool;
@ -111,7 +108,7 @@ private:
std::string _myAddressStr;
std::string _connString;
BlockingQueue< std::pair<nlohmann::json,bool> > _commitQueue;
BlockingQueue<std::pair<nlohmann::json, bool> > _commitQueue;
std::thread _heartbeatThread;
std::thread _membersDbWatcher;
@ -119,7 +116,7 @@ private:
std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS];
std::thread _onlineNotificationThread;
std::unordered_map< std::pair<uint64_t,uint64_t>,NodeOnlineRecord,_PairHasher > _lastOnline;
std::unordered_map<std::pair<uint64_t, uint64_t>, NodeOnlineRecord, _PairHasher> _lastOnline;
mutable std::mutex _lastOnline_l;
mutable std::mutex _readyLock;
@ -129,16 +126,16 @@ private:
int _listenPort;
uint8_t _ssoPsk[48];
RedisConfig *_rc;
RedisConfig* _rc;
std::shared_ptr<sw::redis::Redis> _redis;
std::shared_ptr<sw::redis::RedisCluster> _cluster;
bool _redisMemberStatus;
bool _redisMemberStatus;
smeeclient::SmeeClient *_smee;
smeeclient::SmeeClient* _smee;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif // ZT_CONTROLLER_CV1_HPP
#endif // ZT_CONTROLLER_CV1_HPP
#endif // ZT_CONTROLLER_USE_LIBPQ
#endif // ZT_CONTROLLER_USE_LIBPQ

File diff suppressed because it is too large Load diff

View file

@ -20,51 +20,53 @@
#define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4
#include "../node/Metrics.hpp"
#include "ConnectionPool.hpp"
#include <pqxx/pqxx>
#include "PostgreSQL.hpp"
#include <memory>
#include <pqxx/pqxx>
#include <redis++/redis++.h>
#include "../node/Metrics.hpp"
#include "PostgreSQL.hpp"
namespace ZeroTier {
class CV2 : public DB
{
public:
CV2(const Identity &myId, const char *path, int listenPort);
class CV2 : public DB {
public:
CV2(const Identity& myId, const char* path, int listenPort);
virtual ~CV2();
virtual bool waitForReady();
virtual bool isReady();
virtual bool save(nlohmann::json &record,bool notifyListeners);
virtual bool save(nlohmann::json& record, bool notifyListeners);
virtual void eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch);
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch);
virtual AuthInfo getSSOAuthInfo(const nlohmann::json& member, const std::string& redirectURL);
virtual bool ready() {
virtual bool ready()
{
return _ready == 2;
}
protected:
struct _PairHasher
{
inline std::size_t operator()(const std::pair<uint64_t,uint64_t> &p) const { return (std::size_t)(p.first ^ p.second); }
protected:
struct _PairHasher {
inline std::size_t operator()(const std::pair<uint64_t, uint64_t>& p) const
{
return (std::size_t)(p.first ^ p.second);
}
};
virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners) {
virtual void _memberChanged(nlohmann::json& old, nlohmann::json& memberConfig, bool notifyListeners)
{
DB::_memberChanged(old, memberConfig, notifyListeners);
}
virtual void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners) {
virtual void _networkChanged(nlohmann::json& old, nlohmann::json& networkConfig, bool notifyListeners)
{
DB::_networkChanged(old, networkConfig, notifyListeners);
}
private:
private:
void initializeNetworks();
void initializeMembers();
void heartbeat();
@ -76,10 +78,7 @@ private:
// void notifyNewMember(const std::string &networkID, const std::string &memberID);
enum OverrideMode {
ALLOW_PGBOUNCER_OVERRIDE = 0,
NO_OVERRIDE = 1
};
enum OverrideMode { ALLOW_PGBOUNCER_OVERRIDE = 0, NO_OVERRIDE = 1 };
std::shared_ptr<ConnectionPool<PostgresConnection> > _pool;
@ -88,7 +87,7 @@ private:
std::string _myAddressStr;
std::string _connString;
BlockingQueue< std::pair<nlohmann::json,bool> > _commitQueue;
BlockingQueue<std::pair<nlohmann::json, bool> > _commitQueue;
std::thread _heartbeatThread;
std::thread _membersDbWatcher;
@ -96,7 +95,7 @@ private:
std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS];
std::thread _onlineNotificationThread;
std::unordered_map< std::pair<uint64_t,uint64_t>,NodeOnlineRecord,_PairHasher > _lastOnline;
std::unordered_map<std::pair<uint64_t, uint64_t>, NodeOnlineRecord, _PairHasher> _lastOnline;
mutable std::mutex _lastOnline_l;
mutable std::mutex _readyLock;
@ -107,7 +106,7 @@ private:
uint8_t _ssoPsk[48];
};
} // namespace Zerotier
} // namespace ZeroTier
#endif // ZT_CONTROLLER_CV2_HPP
#endif // ZT_CONTROLLER_USE_LIBPQ
#endif // ZT_CONTROLLER_CV2_HPP
#endif // ZT_CONTROLLER_USE_LIBPQ

View file

@ -14,162 +14,162 @@
#ifndef ZT_CONNECTION_POOL_H_
#define ZT_CONNECTION_POOL_H_
#ifndef _DEBUG
#define _DEBUG(x)
#define _DEBUG(x)
#endif
#include "../node/Metrics.hpp"
#include <deque>
#include <set>
#include <exception>
#include <memory>
#include <mutex>
#include <exception>
#include <set>
#include <string>
namespace ZeroTier {
struct ConnectionUnavailable : std::exception {
char const* what() const throw() {
return "Unable to allocate connection";
};
struct ConnectionUnavailable : std::exception {
char const* what() const throw()
{
return "Unable to allocate connection";
};
};
class Connection {
public:
virtual ~Connection() {};
public:
virtual ~Connection() {};
};
class ConnectionFactory {
public:
virtual ~ConnectionFactory() {};
virtual std::shared_ptr<Connection> create()=0;
public:
virtual ~ConnectionFactory() {};
virtual std::shared_ptr<Connection> create() = 0;
};
struct ConnectionPoolStats {
size_t pool_size;
size_t borrowed_size;
size_t pool_size;
size_t borrowed_size;
};
template<class T>
class ConnectionPool {
public:
ConnectionPool(size_t max_pool_size, size_t min_pool_size, std::shared_ptr<ConnectionFactory> factory)
: m_maxPoolSize(max_pool_size)
, m_minPoolSize(min_pool_size)
, m_factory(factory)
{
Metrics::max_pool_size += max_pool_size;
Metrics::min_pool_size += min_pool_size;
while(m_pool.size() < m_minPoolSize){
m_pool.push_back(m_factory->create());
Metrics::pool_avail++;
}
};
template <class T> class ConnectionPool {
public:
ConnectionPool(size_t max_pool_size, size_t min_pool_size, std::shared_ptr<ConnectionFactory> factory) : m_maxPoolSize(max_pool_size), m_minPoolSize(min_pool_size), m_factory(factory)
{
Metrics::max_pool_size += max_pool_size;
Metrics::min_pool_size += min_pool_size;
while (m_pool.size() < m_minPoolSize) {
m_pool.push_back(m_factory->create());
Metrics::pool_avail++;
}
};
ConnectionPoolStats get_stats() {
std::unique_lock<std::mutex> lock(m_poolMutex);
ConnectionPoolStats get_stats()
{
std::unique_lock<std::mutex> lock(m_poolMutex);
ConnectionPoolStats stats;
stats.pool_size = m_pool.size();
stats.borrowed_size = m_borrowed.size();
ConnectionPoolStats stats;
stats.pool_size = m_pool.size();
stats.borrowed_size = m_borrowed.size();
return stats;
};
return stats;
};
~ConnectionPool() {
};
~ConnectionPool() {};
/**
* Borrow
*
* Borrow a connection for temporary use
*
* When done, either (a) call unborrow() to return it, or (b) (if it's bad) just let it go out of scope. This will cause it to automatically be replaced.
* @retval a shared_ptr to the connection object
*/
std::shared_ptr<T> borrow() {
std::unique_lock<std::mutex> l(m_poolMutex);
while((m_pool.size() + m_borrowed.size()) < m_minPoolSize) {
std::shared_ptr<Connection> conn = m_factory->create();
m_pool.push_back(conn);
Metrics::pool_avail++;
}
/**
* Borrow
*
* Borrow a connection for temporary use
*
* When done, either (a) call unborrow() to return it, or (b) (if it's bad) just let it go out of scope. This will cause it to automatically be replaced.
* @retval a shared_ptr to the connection object
*/
std::shared_ptr<T> borrow()
{
std::unique_lock<std::mutex> l(m_poolMutex);
if(m_pool.size()==0){
if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
try {
std::shared_ptr<Connection> conn = m_factory->create();
m_borrowed.insert(conn);
Metrics::pool_in_use++;
return std::static_pointer_cast<T>(conn);
} catch (std::exception &e) {
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
} else {
for(auto it = m_borrowed.begin(); it != m_borrowed.end(); ++it){
if((*it).unique()) {
// This connection has been abandoned! Destroy it and create a new connection
try {
// If we are able to create a new connection, return it
_DEBUG("Creating new connection to replace discarded connection");
std::shared_ptr<Connection> conn = m_factory->create();
m_borrowed.erase(it);
m_borrowed.insert(conn);
return std::static_pointer_cast<T>(conn);
} catch(std::exception& e) {
// Error creating a replacement connection
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
}
}
// Nothing available
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
}
while ((m_pool.size() + m_borrowed.size()) < m_minPoolSize) {
std::shared_ptr<Connection> conn = m_factory->create();
m_pool.push_back(conn);
Metrics::pool_avail++;
}
// Take one off the front
std::shared_ptr<Connection> conn = m_pool.front();
m_pool.pop_front();
Metrics::pool_avail--;
// Add it to the borrowed list
m_borrowed.insert(conn);
Metrics::pool_in_use++;
return std::static_pointer_cast<T>(conn);
};
if (m_pool.size() == 0) {
if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
try {
std::shared_ptr<Connection> conn = m_factory->create();
m_borrowed.insert(conn);
Metrics::pool_in_use++;
return std::static_pointer_cast<T>(conn);
}
catch (std::exception& e) {
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
}
else {
for (auto it = m_borrowed.begin(); it != m_borrowed.end(); ++it) {
if ((*it).unique()) {
// This connection has been abandoned! Destroy it and create a new connection
try {
// If we are able to create a new connection, return it
_DEBUG("Creating new connection to replace discarded connection");
std::shared_ptr<Connection> conn = m_factory->create();
m_borrowed.erase(it);
m_borrowed.insert(conn);
return std::static_pointer_cast<T>(conn);
}
catch (std::exception& e) {
// Error creating a replacement connection
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
}
}
// Nothing available
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
}
/**
* Unborrow a connection
*
* Only call this if you are returning a working connection. If the connection was bad, just let it go out of scope (so the connection manager can replace it).
* @param the connection
*/
void unborrow(std::shared_ptr<T> conn) {
// Lock
std::unique_lock<std::mutex> lock(m_poolMutex);
m_borrowed.erase(conn);
Metrics::pool_in_use--;
if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
Metrics::pool_avail++;
m_pool.push_back(conn);
}
};
protected:
size_t m_maxPoolSize;
size_t m_minPoolSize;
std::shared_ptr<ConnectionFactory> m_factory;
std::deque<std::shared_ptr<Connection> > m_pool;
std::set<std::shared_ptr<Connection> > m_borrowed;
std::mutex m_poolMutex;
// Take one off the front
std::shared_ptr<Connection> conn = m_pool.front();
m_pool.pop_front();
Metrics::pool_avail--;
// Add it to the borrowed list
m_borrowed.insert(conn);
Metrics::pool_in_use++;
return std::static_pointer_cast<T>(conn);
};
/**
* Unborrow a connection
*
* Only call this if you are returning a working connection. If the connection was bad, just let it go out of scope (so the connection manager can replace it).
* @param the connection
*/
void unborrow(std::shared_ptr<T> conn)
{
// Lock
std::unique_lock<std::mutex> lock(m_poolMutex);
m_borrowed.erase(conn);
Metrics::pool_in_use--;
if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
Metrics::pool_avail++;
m_pool.push_back(conn);
}
};
protected:
size_t m_maxPoolSize;
size_t m_minPoolSize;
std::shared_ptr<ConnectionFactory> m_factory;
std::deque<std::shared_ptr<Connection> > m_pool;
std::set<std::shared_ptr<Connection> > m_borrowed;
std::mutex m_poolMutex;
};
}
} // namespace ZeroTier
#endif

View file

@ -2,17 +2,17 @@
#ifdef ZT_CONTROLLER_USE_LIBPQ
#include <sstream>
#include <iomanip>
#include <sstream>
namespace ZeroTier {
const char *_timestr()
const char* _timestr()
{
time_t t = time(0);
char *ts = ctime(&t);
char *p = ts;
if (!p)
char* ts = ctime(&t);
char* p = ts;
if (! p)
return "";
while (*p) {
if (*p == '\n') {
@ -24,39 +24,41 @@ const char *_timestr()
return ts;
}
std::vector<std::string> split(std::string str, char delim){
std::vector<std::string> split(std::string str, char delim)
{
std::istringstream iss(str);
std::vector<std::string> tokens;
std::string item;
while(std::getline(iss, item, delim)) {
while (std::getline(iss, item, delim)) {
tokens.push_back(item);
}
return tokens;
}
std::string url_encode(const std::string &value) {
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
std::string url_encode(const std::string& value)
{
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
std::string::value_type c = (*i);
for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
std::string::value_type c = (*i);
// Keep alphanumeric and other accepted characters intact
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
continue;
}
// Keep alphanumeric and other accepted characters intact
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
continue;
}
// Any other characters are percent-encoded
escaped << std::uppercase;
escaped << '%' << std::setw(2) << int((unsigned char) c);
escaped << std::nouppercase;
}
// Any other characters are percent-encoded
escaped << std::uppercase;
escaped << '%' << std::setw(2) << int((unsigned char)c);
escaped << std::nouppercase;
}
return escaped.str();
return escaped.str();
}
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -1,16 +1,16 @@
#ifndef ZT_CTLUTIL_HPP
#define ZT_CTLUTIL_HPP
#include <vector>
#include <string>
#include <vector>
namespace ZeroTier {
const char *_timestr();
const char* _timestr();
std::vector<std::string> split(std::string str, char delim);
std::vector<std::string> split(std::string str, char delim);
std::string url_encode(const std::string &value);
}
std::string url_encode(const std::string& value);
} // namespace ZeroTier
#endif // namespace ZeroTier
#endif // namespace ZeroTier

View file

@ -12,77 +12,114 @@
/****/
#include "DB.hpp"
#include "EmbeddedNetworkController.hpp"
#include "../node/Metrics.hpp"
#include <chrono>
#include "../node/Metrics.hpp"
#include "EmbeddedNetworkController.hpp"
#include <algorithm>
#include <chrono>
#include <stdexcept>
using json = nlohmann::json;
namespace ZeroTier {
void DB::initNetwork(nlohmann::json &network)
void DB::initNetwork(nlohmann::json& network)
{
if (!network.count("private")) network["private"] = true;
if (!network.count("creationTime")) network["creationTime"] = OSUtils::now();
if (!network.count("name")) network["name"] = "";
if (!network.count("multicastLimit")) network["multicastLimit"] = (uint64_t)32;
if (!network.count("enableBroadcast")) network["enableBroadcast"] = true;
if (!network.count("v4AssignMode")) network["v4AssignMode"] = {{"zt",false}};
if (!network.count("v6AssignMode")) network["v6AssignMode"] = {{"rfc4193",false},{"zt",false},{"6plane",false}};
if (!network.count("authTokens")) network["authTokens"] = {{}};
if (!network.count("capabilities")) network["capabilities"] = nlohmann::json::array();
if (!network.count("tags")) network["tags"] = nlohmann::json::array();
if (!network.count("routes")) network["routes"] = nlohmann::json::array();
if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array();
if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU;
if (!network.count("remoteTraceTarget")) network["remoteTraceTarget"] = nlohmann::json();
if (!network.count("removeTraceLevel")) network["remoteTraceLevel"] = 0;
if (!network.count("rulesSource")) network["rulesSource"] = "";
if (!network.count("rules")) {
if (! network.count("private"))
network["private"] = true;
if (! network.count("creationTime"))
network["creationTime"] = OSUtils::now();
if (! network.count("name"))
network["name"] = "";
if (! network.count("multicastLimit"))
network["multicastLimit"] = (uint64_t)32;
if (! network.count("enableBroadcast"))
network["enableBroadcast"] = true;
if (! network.count("v4AssignMode"))
network["v4AssignMode"] = { { "zt", false } };
if (! network.count("v6AssignMode"))
network["v6AssignMode"] = { { "rfc4193", false }, { "zt", false }, { "6plane", false } };
if (! network.count("authTokens"))
network["authTokens"] = { {} };
if (! network.count("capabilities"))
network["capabilities"] = nlohmann::json::array();
if (! network.count("tags"))
network["tags"] = nlohmann::json::array();
if (! network.count("routes"))
network["routes"] = nlohmann::json::array();
if (! network.count("ipAssignmentPools"))
network["ipAssignmentPools"] = nlohmann::json::array();
if (! network.count("mtu"))
network["mtu"] = ZT_DEFAULT_MTU;
if (! network.count("remoteTraceTarget"))
network["remoteTraceTarget"] = nlohmann::json();
if (! network.count("removeTraceLevel"))
network["remoteTraceLevel"] = 0;
if (! network.count("rulesSource"))
network["rulesSource"] = "";
if (! network.count("rules")) {
// If unspecified, rules are set to allow anything and behave like a flat L2 segment
network["rules"] = {{
{ "not",false },
{ "or", false },
{ "type","ACTION_ACCEPT" }
}};
network["rules"] = { { { "not", false }, { "or", false }, { "type", "ACTION_ACCEPT" } } };
}
if (!network.count("dns")) network["dns"] = nlohmann::json::array();
if (!network.count("ssoEnabled")) network["ssoEnabled"] = false;
if (!network.count("clientId")) network["clientId"] = "";
if (!network.count("authorizationEndpoint")) network["authorizationEndpoint"] = "";
if (! network.count("dns"))
network["dns"] = nlohmann::json::array();
if (! network.count("ssoEnabled"))
network["ssoEnabled"] = false;
if (! network.count("clientId"))
network["clientId"] = "";
if (! network.count("authorizationEndpoint"))
network["authorizationEndpoint"] = "";
network["objtype"] = "network";
}
void DB::initMember(nlohmann::json &member)
void DB::initMember(nlohmann::json& member)
{
if (!member.count("authorized")) member["authorized"] = false;
if (!member.count("ssoExempt")) member["ssoExempt"] = false;
if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array();
if (!member.count("activeBridge")) member["activeBridge"] = false;
if (!member.count("tags")) member["tags"] = nlohmann::json::array();
if (!member.count("capabilities")) member["capabilities"] = nlohmann::json::array();
if (!member.count("creationTime")) member["creationTime"] = OSUtils::now();
if (!member.count("noAutoAssignIps")) member["noAutoAssignIps"] = false;
if (!member.count("revision")) member["revision"] = 0ULL;
if (!member.count("lastDeauthorizedTime")) member["lastDeauthorizedTime"] = 0ULL;
if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL;
if (!member.count("lastAuthorizedCredentialType")) member["lastAuthorizedCredentialType"] = nlohmann::json();
if (!member.count("lastAuthorizedCredential")) member["lastAuthorizedCredential"] = nlohmann::json();
if (!member.count("authenticationExpiryTime")) member["authenticationExpiryTime"] = 0LL;
if (!member.count("vMajor")) member["vMajor"] = -1;
if (!member.count("vMinor")) member["vMinor"] = -1;
if (!member.count("vRev")) member["vRev"] = -1;
if (!member.count("vProto")) member["vProto"] = -1;
if (!member.count("remoteTraceTarget")) member["remoteTraceTarget"] = nlohmann::json();
if (!member.count("removeTraceLevel")) member["remoteTraceLevel"] = 0;
if (! member.count("authorized"))
member["authorized"] = false;
if (! member.count("ssoExempt"))
member["ssoExempt"] = false;
if (! member.count("ipAssignments"))
member["ipAssignments"] = nlohmann::json::array();
if (! member.count("activeBridge"))
member["activeBridge"] = false;
if (! member.count("tags"))
member["tags"] = nlohmann::json::array();
if (! member.count("capabilities"))
member["capabilities"] = nlohmann::json::array();
if (! member.count("creationTime"))
member["creationTime"] = OSUtils::now();
if (! member.count("noAutoAssignIps"))
member["noAutoAssignIps"] = false;
if (! member.count("revision"))
member["revision"] = 0ULL;
if (! member.count("lastDeauthorizedTime"))
member["lastDeauthorizedTime"] = 0ULL;
if (! member.count("lastAuthorizedTime"))
member["lastAuthorizedTime"] = 0ULL;
if (! member.count("lastAuthorizedCredentialType"))
member["lastAuthorizedCredentialType"] = nlohmann::json();
if (! member.count("lastAuthorizedCredential"))
member["lastAuthorizedCredential"] = nlohmann::json();
if (! member.count("authenticationExpiryTime"))
member["authenticationExpiryTime"] = 0LL;
if (! member.count("vMajor"))
member["vMajor"] = -1;
if (! member.count("vMinor"))
member["vMinor"] = -1;
if (! member.count("vRev"))
member["vRev"] = -1;
if (! member.count("vProto"))
member["vProto"] = -1;
if (! member.count("remoteTraceTarget"))
member["remoteTraceTarget"] = nlohmann::json();
if (! member.count("removeTraceLevel"))
member["remoteTraceLevel"] = 0;
member["objtype"] = "member";
}
void DB::cleanNetwork(nlohmann::json &network)
void DB::cleanNetwork(nlohmann::json& network)
{
network.erase("clock");
network.erase("authorizedMemberCount");
@ -91,21 +128,25 @@ void DB::cleanNetwork(nlohmann::json &network)
network.erase("lastModified");
}
void DB::cleanMember(nlohmann::json &member)
void DB::cleanMember(nlohmann::json& member)
{
member.erase("clock");
member.erase("physicalAddr");
member.erase("recentLog");
member.erase("lastModified");
member.erase("lastRequestMetaData");
member.erase("authenticationURL"); // computed
member.erase("authenticationClientID"); // computed
member.erase("authenticationURL"); // computed
member.erase("authenticationClientID"); // computed
}
DB::DB() {}
DB::~DB() {}
DB::DB()
{
}
DB::~DB()
{
}
bool DB::get(const uint64_t networkId,nlohmann::json &network)
bool DB::get(const uint64_t networkId, nlohmann::json& network)
{
waitForReady();
Metrics::db_get_network++;
@ -124,7 +165,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network)
return true;
}
bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member)
bool DB::get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member)
{
waitForReady();
Metrics::db_get_network_and_member++;
@ -147,7 +188,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem
return true;
}
bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,NetworkSummaryInfo &info)
bool DB::get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member, NetworkSummaryInfo& info)
{
waitForReady();
Metrics::db_get_network_and_member_and_summary++;
@ -162,7 +203,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem
{
std::shared_lock<std::shared_mutex> l2(nw->lock);
network = nw->config;
_fillSummaryInfo(nw,info);
_fillSummaryInfo(nw, info);
auto m = nw->members.find(memberId);
if (m == nw->members.end())
return false;
@ -171,7 +212,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem
return true;
}
bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members)
bool DB::get(const uint64_t networkId, nlohmann::json& network, std::vector<nlohmann::json>& members)
{
waitForReady();
Metrics::db_get_member_list++;
@ -186,23 +227,23 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohma
{
std::shared_lock<std::shared_mutex> l2(nw->lock);
network = nw->config;
for(auto m=nw->members.begin();m!=nw->members.end();++m) {
for (auto m = nw->members.begin(); m != nw->members.end(); ++m) {
members.push_back(m->second);
}
}
return true;
}
void DB::networks(std::set<uint64_t> &networks)
void DB::networks(std::set<uint64_t>& networks)
{
waitForReady();
Metrics::db_get_network_list++;
std::shared_lock<std::shared_mutex> l(_networks_l);
for(auto n=_networks.begin();n!=_networks.end();++n)
for (auto n = _networks.begin(); n != _networks.end(); ++n)
networks.insert(n->first);
}
void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners)
void DB::_memberChanged(nlohmann::json& old, nlohmann::json& memberConfig, bool notifyListeners)
{
Metrics::db_member_change++;
uint64_t memberId = 0;
@ -212,9 +253,9 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
std::shared_ptr<_Network> nw;
if (old.is_object()) {
memberId = OSUtils::jsonIntHex(old["id"],0ULL);
networkId = OSUtils::jsonIntHex(old["nwid"],0ULL);
if ((memberId)&&(networkId)) {
memberId = OSUtils::jsonIntHex(old["id"], 0ULL);
networkId = OSUtils::jsonIntHex(old["nwid"], 0ULL);
if ((memberId) && (networkId)) {
{
std::unique_lock<std::shared_mutex> l(_networks_l);
auto nw2 = _networks.find(networkId);
@ -224,17 +265,17 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
}
if (nw) {
std::unique_lock<std::shared_mutex> l(nw->lock);
if (OSUtils::jsonBool(old["activeBridge"],false)) {
if (OSUtils::jsonBool(old["activeBridge"], false)) {
nw->activeBridgeMembers.erase(memberId);
}
wasAuth = OSUtils::jsonBool(old["authorized"],false);
wasAuth = OSUtils::jsonBool(old["authorized"], false);
if (wasAuth) {
nw->authorizedMembers.erase(memberId);
}
json &ips = old["ipAssignments"];
json& ips = old["ipAssignments"];
if (ips.is_array()) {
for(unsigned long i=0;i<ips.size();++i) {
json &ipj = ips[i];
for (unsigned long i = 0; i < ips.size(); ++i) {
json& ipj = ips[i];
if (ipj.is_string()) {
const std::string ips = ipj;
InetAddress ipa(ips.c_str());
@ -248,14 +289,14 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
}
if (memberConfig.is_object()) {
if (!nw) {
memberId = OSUtils::jsonIntHex(memberConfig["id"],0ULL);
networkId = OSUtils::jsonIntHex(memberConfig["nwid"],0ULL);
if ((!memberId)||(!networkId))
if (! nw) {
memberId = OSUtils::jsonIntHex(memberConfig["id"], 0ULL);
networkId = OSUtils::jsonIntHex(memberConfig["nwid"], 0ULL);
if ((! memberId) || (! networkId))
return;
std::unique_lock<std::shared_mutex> l(_networks_l);
std::shared_ptr<_Network> &nw2 = _networks[networkId];
if (!nw2)
std::shared_ptr<_Network>& nw2 = _networks[networkId];
if (! nw2)
nw2.reset(new _Network);
nw = nw2;
}
@ -265,18 +306,18 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
nw->members[memberId] = memberConfig;
if (OSUtils::jsonBool(memberConfig["activeBridge"],false)) {
if (OSUtils::jsonBool(memberConfig["activeBridge"], false)) {
nw->activeBridgeMembers.insert(memberId);
}
isAuth = OSUtils::jsonBool(memberConfig["authorized"],false);
isAuth = OSUtils::jsonBool(memberConfig["authorized"], false);
if (isAuth) {
Metrics::member_auths++;
nw->authorizedMembers.insert(memberId);
}
json &ips = memberConfig["ipAssignments"];
json& ips = memberConfig["ipAssignments"];
if (ips.is_array()) {
for(unsigned long i=0;i<ips.size();++i) {
json &ipj = ips[i];
for (unsigned long i = 0; i < ips.size(); ++i) {
json& ipj = ips[i];
if (ipj.is_string()) {
const std::string ips = ipj;
InetAddress ipa(ips.c_str());
@ -286,8 +327,8 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
}
}
if (!isAuth) {
const int64_t ldt = (int64_t)OSUtils::jsonInt(memberConfig["lastDeauthorizedTime"],0ULL);
if (! isAuth) {
const int64_t ldt = (int64_t)OSUtils::jsonInt(memberConfig["lastDeauthorizedTime"], 0ULL);
if (ldt > nw->mostRecentDeauthTime)
nw->mostRecentDeauthTime = ldt;
}
@ -295,11 +336,12 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
if (notifyListeners) {
std::unique_lock<std::shared_mutex> ll(_changeListeners_l);
for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
(*i)->onNetworkMemberUpdate(this,networkId,memberId,memberConfig);
for (auto i = _changeListeners.begin(); i != _changeListeners.end(); ++i) {
(*i)->onNetworkMemberUpdate(this, networkId, memberId, memberConfig);
}
}
} else if (memberId) {
}
else if (memberId) {
if (nw) {
std::unique_lock<std::shared_mutex> l(nw->lock);
nw->members.erase(memberId);
@ -307,7 +349,7 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
if (networkId) {
std::unique_lock<std::shared_mutex> l(_networks_l);
auto er = _networkByMember.equal_range(memberId);
for(auto i=er.first;i!=er.second;++i) {
for (auto i = er.first; i != er.second; ++i) {
if (i->second == networkId) {
_networkByMember.erase(i);
break;
@ -317,40 +359,45 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
}
if (notifyListeners) {
if(networkId != 0 && memberId != 0 && old.is_object() && !memberConfig.is_object()) {
if (networkId != 0 && memberId != 0 && old.is_object() && ! memberConfig.is_object()) {
// member delete
Metrics::member_count--;
} else if (networkId != 0 && memberId != 0 && !old.is_object() && memberConfig.is_object()) {
}
else if (networkId != 0 && memberId != 0 && ! old.is_object() && memberConfig.is_object()) {
// new member
Metrics::member_count++;
}
if (!wasAuth && isAuth) {
if (! wasAuth && isAuth) {
Metrics::member_auths++;
} else if (wasAuth && !isAuth) {
}
else if (wasAuth && ! isAuth) {
Metrics::member_deauths++;
} else {
}
else {
Metrics::member_changes++;
}
}
if ((notifyListeners)&&((wasAuth)&&(!isAuth)&&(networkId)&&(memberId))) {
if ((notifyListeners) && ((wasAuth) && (! isAuth) && (networkId) && (memberId))) {
std::unique_lock<std::shared_mutex> ll(_changeListeners_l);
for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
(*i)->onNetworkMemberDeauthorize(this,networkId,memberId);
for (auto i = _changeListeners.begin(); i != _changeListeners.end(); ++i) {
(*i)->onNetworkMemberDeauthorize(this, networkId, memberId);
}
}
}
void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners)
void DB::_networkChanged(nlohmann::json& old, nlohmann::json& networkConfig, bool notifyListeners)
{
Metrics::db_network_change++;
if (notifyListeners) {
if (old.is_object() && old.contains("id") && networkConfig.is_object() && networkConfig.contains("id")) {
Metrics::network_changes++;
} else if (!old.is_object() && networkConfig.is_object() && networkConfig.contains("id")) {
}
else if (! old.is_object() && networkConfig.is_object() && networkConfig.contains("id")) {
Metrics::network_count++;
} else if (old.is_object() && old.contains("id") && !networkConfig.is_object()) {
}
else if (old.is_object() && old.contains("id") && ! networkConfig.is_object()) {
Metrics::network_count--;
}
}
@ -362,8 +409,8 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool
std::shared_ptr<_Network> nw;
{
std::unique_lock<std::shared_mutex> l(_networks_l);
std::shared_ptr<_Network> &nw2 = _networks[networkId];
if (!nw2)
std::shared_ptr<_Network>& nw2 = _networks[networkId];
if (! nw2)
nw2.reset(new _Network);
nw = nw2;
}
@ -373,12 +420,13 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool
}
if (notifyListeners) {
std::unique_lock<std::shared_mutex> ll(_changeListeners_l);
for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
(*i)->onNetworkUpdate(this,networkId,networkConfig);
for (auto i = _changeListeners.begin(); i != _changeListeners.end(); ++i) {
(*i)->onNetworkUpdate(this, networkId, networkConfig);
}
}
}
} else if (old.is_object()) {
}
else if (old.is_object()) {
const std::string ids = old["id"];
const uint64_t networkId = Utils::hexStrToU64(ids.c_str());
if (networkId) {
@ -387,15 +435,16 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool
nlohmann::json network;
std::vector<nlohmann::json> members;
this->get(networkId, network, members);
for(auto i=members.begin();i!=members.end();++i) {
for (auto i = members.begin(); i != members.end(); ++i) {
const std::string nodeID = (*i)["id"];
const uint64_t memberId = Utils::hexStrToU64(nodeID.c_str());
std::unique_lock<std::shared_mutex> ll(_changeListeners_l);
for(auto j=_changeListeners.begin();j!=_changeListeners.end();++j) {
(*j)->onNetworkMemberDeauthorize(this,networkId,memberId);
for (auto j = _changeListeners.begin(); j != _changeListeners.end(); ++j) {
(*j)->onNetworkMemberDeauthorize(this, networkId, memberId);
}
}
} catch (std::exception &e) {
}
catch (std::exception& e) {
std::cerr << "Error deauthorizing members on network delete: " << e.what() << std::endl;
}
@ -406,17 +455,17 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool
}
}
void DB::_fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info)
void DB::_fillSummaryInfo(const std::shared_ptr<_Network>& nw, NetworkSummaryInfo& info)
{
for(auto ab=nw->activeBridgeMembers.begin();ab!=nw->activeBridgeMembers.end();++ab)
for (auto ab = nw->activeBridgeMembers.begin(); ab != nw->activeBridgeMembers.end(); ++ab)
info.activeBridges.push_back(Address(*ab));
std::sort(info.activeBridges.begin(),info.activeBridges.end());
for(auto ip=nw->allocatedIps.begin();ip!=nw->allocatedIps.end();++ip)
std::sort(info.activeBridges.begin(), info.activeBridges.end());
for (auto ip = nw->allocatedIps.begin(); ip != nw->allocatedIps.end(); ++ip)
info.allocatedIps.push_back(*ip);
std::sort(info.allocatedIps.begin(),info.allocatedIps.end());
std::sort(info.allocatedIps.begin(), info.allocatedIps.end());
info.authorizedMemberCount = (unsigned long)nw->authorizedMembers.size();
info.totalMemberCount = (unsigned long)nw->members.size();
info.mostRecentDeauthTime = nw->mostRecentDeauthTime;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,49 +14,36 @@
#ifndef ZT_CONTROLLER_DB_HPP
#define ZT_CONTROLLER_DB_HPP
//#define ZT_CONTROLLER_USE_LIBPQ
// #define ZT_CONTROLLER_USE_LIBPQ
#include "../node/Constants.hpp"
#include "../node/Identity.hpp"
#include "../node/InetAddress.hpp"
#include "../osdep/OSUtils.hpp"
#include "../osdep/BlockingQueue.hpp"
#include "../osdep/OSUtils.hpp"
#include <atomic>
#include <map>
#include <memory>
#include <nlohmann/json.hpp>
#include <prometheus/simpleapi.h>
#include <set>
#include <shared_mutex>
#include <string>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <atomic>
#include <shared_mutex>
#include <set>
#include <map>
#include <nlohmann/json.hpp>
#include <prometheus/simpleapi.h>
#define ZT_MEMBER_AUTH_TIMEOUT_NOTIFY_BEFORE 25000
namespace ZeroTier
{
namespace ZeroTier {
struct AuthInfo
{
public:
AuthInfo()
: enabled(false)
, version(0)
, authenticationURL()
, authenticationExpiryTime(0)
, issuerURL()
, centralAuthURL()
, ssoNonce()
, ssoState()
, ssoClientID()
, ssoProvider("default")
{}
struct AuthInfo {
public:
AuthInfo() : enabled(false), version(0), authenticationURL(), authenticationExpiryTime(0), issuerURL(), centralAuthURL(), ssoNonce(), ssoState(), ssoClientID(), ssoProvider("default")
{
}
bool enabled;
uint64_t version;
@ -73,26 +60,35 @@ public:
/**
* Base class with common infrastructure for all controller DB implementations
*/
class DB
{
class DB {
#ifdef ZT_CONTROLLER_USE_LIBPQ
friend class MemberNotificationReceiver;
friend class NetworkNotificationReceiver;
#endif
public:
class ChangeListener
{
public:
ChangeListener() {}
virtual ~ChangeListener() {}
virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network) {}
virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member) {}
virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId) {}
public:
class ChangeListener {
public:
ChangeListener()
{
}
virtual ~ChangeListener()
{
}
virtual void onNetworkUpdate(const void* db, uint64_t networkId, const nlohmann::json& network)
{
}
virtual void onNetworkMemberUpdate(const void* db, uint64_t networkId, uint64_t memberId, const nlohmann::json& member)
{
}
virtual void onNetworkMemberDeauthorize(const void* db, uint64_t networkId, uint64_t memberId)
{
}
};
struct NetworkSummaryInfo
{
NetworkSummaryInfo() : authorizedMemberCount(0),totalMemberCount(0),mostRecentDeauthTime(0) {}
struct NetworkSummaryInfo {
NetworkSummaryInfo() : authorizedMemberCount(0), totalMemberCount(0), mostRecentDeauthTime(0)
{
}
std::vector<Address> activeBridges;
std::vector<InetAddress> allocatedIps;
unsigned long authorizedMemberCount;
@ -100,10 +96,10 @@ public:
int64_t mostRecentDeauthTime;
};
static void initNetwork(nlohmann::json &network);
static void initMember(nlohmann::json &member);
static void cleanNetwork(nlohmann::json &network);
static void cleanMember(nlohmann::json &member);
static void initNetwork(nlohmann::json& network);
static void initMember(nlohmann::json& member);
static void cleanNetwork(nlohmann::json& network);
static void cleanMember(nlohmann::json& member);
DB();
virtual ~DB();
@ -117,42 +113,44 @@ public:
return (_networks.find(networkId) != _networks.end());
}
bool get(const uint64_t networkId,nlohmann::json &network);
bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member);
bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,NetworkSummaryInfo &info);
bool get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members);
bool get(const uint64_t networkId, nlohmann::json& network);
bool get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member);
bool get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member, NetworkSummaryInfo& info);
bool get(const uint64_t networkId, nlohmann::json& network, std::vector<nlohmann::json>& members);
void networks(std::set<uint64_t> &networks);
void networks(std::set<uint64_t>& networks);
template<typename F>
inline void each(F f)
template <typename F> inline void each(F f)
{
nlohmann::json nullJson;
std::unique_lock<std::shared_mutex> lck(_networks_l);
for(auto nw=_networks.begin();nw!=_networks.end();++nw) {
f(nw->first,nw->second->config,0,nullJson); // first provide network with 0 for member ID
for(auto m=nw->second->members.begin();m!=nw->second->members.end();++m) {
f(nw->first,nw->second->config,m->first,m->second);
for (auto nw = _networks.begin(); nw != _networks.end(); ++nw) {
f(nw->first, nw->second->config, 0, nullJson); // first provide network with 0 for member ID
for (auto m = nw->second->members.begin(); m != nw->second->members.end(); ++m) {
f(nw->first, nw->second->config, m->first, m->second);
}
}
}
virtual bool save(nlohmann::json &record,bool notifyListeners) = 0;
virtual bool save(nlohmann::json& record, bool notifyListeners) = 0;
virtual void eraseNetwork(const uint64_t networkId) = 0;
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId) = 0;
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) = 0;
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch) = 0;
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId) = 0;
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress) = 0;
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch) = 0;
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) { return AuthInfo(); }
virtual AuthInfo getSSOAuthInfo(const nlohmann::json& member, const std::string& redirectURL)
{
return AuthInfo();
}
inline void addListener(DB::ChangeListener *const listener)
inline void addListener(DB::ChangeListener* const listener)
{
std::unique_lock<std::shared_mutex> l(_changeListeners_l);
_changeListeners.push_back(listener);
}
protected:
static inline bool _compareRecords(const nlohmann::json &a,const nlohmann::json &b)
protected:
static inline bool _compareRecords(const nlohmann::json& a, const nlohmann::json& b)
{
if (a.is_object() == b.is_object()) {
if (a.is_object()) {
@ -160,10 +158,10 @@ protected:
return false;
auto amap = a.get<nlohmann::json::object_t>();
auto bmap = b.get<nlohmann::json::object_t>();
for(auto ai=amap.begin();ai!=amap.end();++ai) {
if (ai->first != "revision") { // ignore revision, compare only non-revision-counter fields
for (auto ai = amap.begin(); ai != amap.end(); ++ai) {
if (ai->first != "revision") { // ignore revision, compare only non-revision-counter fields
auto bi = bmap.find(ai->first);
if ((bi == bmap.end())||(bi->second != ai->second))
if ((bi == bmap.end()) || (bi->second != ai->second))
return false;
}
}
@ -174,29 +172,30 @@ protected:
return false;
}
struct _Network
{
_Network() : mostRecentDeauthTime(0) {}
struct _Network {
_Network() : mostRecentDeauthTime(0)
{
}
nlohmann::json config;
std::unordered_map<uint64_t,nlohmann::json> members;
std::unordered_map<uint64_t, nlohmann::json> members;
std::unordered_set<uint64_t> activeBridgeMembers;
std::unordered_set<uint64_t> authorizedMembers;
std::unordered_set<InetAddress,InetAddress::Hasher> allocatedIps;
std::unordered_set<InetAddress, InetAddress::Hasher> allocatedIps;
int64_t mostRecentDeauthTime;
std::shared_mutex lock;
};
virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners);
virtual void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners);
void _fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info);
virtual void _memberChanged(nlohmann::json& old, nlohmann::json& memberConfig, bool notifyListeners);
virtual void _networkChanged(nlohmann::json& old, nlohmann::json& networkConfig, bool notifyListeners);
void _fillSummaryInfo(const std::shared_ptr<_Network>& nw, NetworkSummaryInfo& info);
std::vector<DB::ChangeListener *> _changeListeners;
std::unordered_map< uint64_t,std::shared_ptr<_Network> > _networks;
std::unordered_multimap< uint64_t,uint64_t > _networkByMember;
std::vector<DB::ChangeListener*> _changeListeners;
std::unordered_map<uint64_t, std::shared_ptr<_Network> > _networks;
std::unordered_multimap<uint64_t, uint64_t> _networkByMember;
mutable std::shared_mutex _changeListeners_l;
mutable std::shared_mutex _networks_l;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -15,56 +15,54 @@
namespace ZeroTier {
DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener)
: _listener(listener)
, _running(true)
, _syncCheckerThread()
, _dbs()
, _dbs_l()
DBMirrorSet::DBMirrorSet(DB::ChangeListener* listener) : _listener(listener), _running(true), _syncCheckerThread(), _dbs(), _dbs_l()
{
_syncCheckerThread = std::thread([this]() {
for(;;) {
for(int i=0;i<120;++i) { // 1 minute delay between checks
if (!_running)
for (;;) {
for (int i = 0; i < 120; ++i) { // 1 minute delay between checks
if (! _running)
return;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
std::vector< std::shared_ptr<DB> > dbs;
std::vector<std::shared_ptr<DB> > dbs;
{
std::unique_lock<std::shared_mutex> l(_dbs_l);
if (_dbs.size() <= 1)
continue; // no need to do this if there's only one DB, so skip the iteration
continue; // no need to do this if there's only one DB, so skip the iteration
dbs = _dbs;
}
for(auto db=dbs.begin();db!=dbs.end();++db) {
(*db)->each([&dbs,&db](uint64_t networkId,const nlohmann::json &network,uint64_t memberId,const nlohmann::json &member) {
for (auto db = dbs.begin(); db != dbs.end(); ++db) {
(*db)->each([&dbs, &db](uint64_t networkId, const nlohmann::json& network, uint64_t memberId, const nlohmann::json& member) {
try {
if (network.is_object()) {
if (memberId == 0) {
for(auto db2=dbs.begin();db2!=dbs.end();++db2) {
for (auto db2 = dbs.begin(); db2 != dbs.end(); ++db2) {
if (db->get() != db2->get()) {
nlohmann::json nw2;
if ((!(*db2)->get(networkId,nw2))||((nw2.is_object())&&(OSUtils::jsonInt(nw2["revision"],0) < OSUtils::jsonInt(network["revision"],0)))) {
if ((! (*db2)->get(networkId, nw2)) || ((nw2.is_object()) && (OSUtils::jsonInt(nw2["revision"], 0) < OSUtils::jsonInt(network["revision"], 0)))) {
nw2 = network;
(*db2)->save(nw2,false);
(*db2)->save(nw2, false);
}
}
}
} else if (member.is_object()) {
for(auto db2=dbs.begin();db2!=dbs.end();++db2) {
}
else if (member.is_object()) {
for (auto db2 = dbs.begin(); db2 != dbs.end(); ++db2) {
if (db->get() != db2->get()) {
nlohmann::json nw2,m2;
if ((!(*db2)->get(networkId,nw2,memberId,m2))||((m2.is_object())&&(OSUtils::jsonInt(m2["revision"],0) < OSUtils::jsonInt(member["revision"],0)))) {
nlohmann::json nw2, m2;
if ((! (*db2)->get(networkId, nw2, memberId, m2)) || ((m2.is_object()) && (OSUtils::jsonInt(m2["revision"], 0) < OSUtils::jsonInt(member["revision"], 0)))) {
m2 = member;
(*db2)->save(m2,false);
(*db2)->save(m2, false);
}
}
}
}
}
} catch ( ... ) {} // skip entries that generate JSON errors
}
catch (...) {
} // skip entries that generate JSON errors
});
}
}
@ -80,58 +78,58 @@ DBMirrorSet::~DBMirrorSet()
bool DBMirrorSet::hasNetwork(const uint64_t networkId) const
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if ((*d)->hasNetwork(networkId))
return true;
}
return false;
}
bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network)
bool DBMirrorSet::get(const uint64_t networkId, nlohmann::json& network)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
if ((*d)->get(networkId,network)) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if ((*d)->get(networkId, network)) {
return true;
}
}
return false;
}
bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member)
bool DBMirrorSet::get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
if ((*d)->get(networkId,network,memberId,member))
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if ((*d)->get(networkId, network, memberId, member))
return true;
}
return false;
}
bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,DB::NetworkSummaryInfo &info)
bool DBMirrorSet::get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member, DB::NetworkSummaryInfo& info)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
if ((*d)->get(networkId,network,memberId,member,info))
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if ((*d)->get(networkId, network, memberId, member, info))
return true;
}
return false;
}
bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members)
bool DBMirrorSet::get(const uint64_t networkId, nlohmann::json& network, std::vector<nlohmann::json>& members)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
if ((*d)->get(networkId,network,members))
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if ((*d)->get(networkId, network, members))
return true;
}
return false;
}
AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL)
AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json& member, const std::string& redirectURL)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
AuthInfo info = (*d)->getSSOAuthInfo(member, redirectURL);
if (info.enabled) {
return info;
@ -140,10 +138,10 @@ AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::st
return AuthInfo();
}
void DBMirrorSet::networks(std::set<uint64_t> &networks)
void DBMirrorSet::networks(std::set<uint64_t>& networks)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
(*d)->networks(networks);
}
}
@ -152,7 +150,7 @@ bool DBMirrorSet::waitForReady()
{
bool r = false;
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
r |= (*d)->waitForReady();
}
return r;
@ -161,30 +159,31 @@ bool DBMirrorSet::waitForReady()
bool DBMirrorSet::isReady()
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
if (!(*d)->isReady())
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if (! (*d)->isReady())
return false;
}
return true;
}
bool DBMirrorSet::save(nlohmann::json &record,bool notifyListeners)
bool DBMirrorSet::save(nlohmann::json& record, bool notifyListeners)
{
std::vector< std::shared_ptr<DB> > dbs;
std::vector<std::shared_ptr<DB> > dbs;
{
std::unique_lock<std::shared_mutex> l(_dbs_l);
dbs = _dbs;
}
if (notifyListeners) {
for(auto d=dbs.begin();d!=dbs.end();++d) {
if ((*d)->save(record,true))
for (auto d = dbs.begin(); d != dbs.end(); ++d) {
if ((*d)->save(record, true))
return true;
}
return false;
} else {
}
else {
bool modified = false;
for(auto d=dbs.begin();d!=dbs.end();++d) {
modified |= (*d)->save(record,false);
for (auto d = dbs.begin(); d != dbs.end(); ++d) {
modified |= (*d)->save(record, false);
}
return modified;
}
@ -193,58 +192,59 @@ bool DBMirrorSet::save(nlohmann::json &record,bool notifyListeners)
void DBMirrorSet::eraseNetwork(const uint64_t networkId)
{
std::unique_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
(*d)->eraseNetwork(networkId);
}
}
void DBMirrorSet::eraseMember(const uint64_t networkId,const uint64_t memberId)
void DBMirrorSet::eraseMember(const uint64_t networkId, const uint64_t memberId)
{
std::unique_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
(*d)->eraseMember(networkId,memberId);
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
(*d)->eraseMember(networkId, memberId);
}
}
void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch) {
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
(*d)->nodeIsOnline(networkId,memberId,physicalAddress,osArch);
}
}
void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
void DBMirrorSet::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch)
{
this->nodeIsOnline(networkId,memberId,physicalAddress,"unknown/unknown");
std::shared_lock<std::shared_mutex> l(_dbs_l);
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
(*d)->nodeIsOnline(networkId, memberId, physicalAddress, osArch);
}
}
void DBMirrorSet::onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network)
void DBMirrorSet::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress)
{
this->nodeIsOnline(networkId, memberId, physicalAddress, "unknown/unknown");
}
void DBMirrorSet::onNetworkUpdate(const void* db, uint64_t networkId, const nlohmann::json& network)
{
nlohmann::json record(network);
std::unique_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if (d->get() != db) {
(*d)->save(record,false);
(*d)->save(record, false);
}
}
_listener->onNetworkUpdate(this,networkId,network);
_listener->onNetworkUpdate(this, networkId, network);
}
void DBMirrorSet::onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member)
void DBMirrorSet::onNetworkMemberUpdate(const void* db, uint64_t networkId, uint64_t memberId, const nlohmann::json& member)
{
nlohmann::json record(member);
std::unique_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if (d->get() != db) {
(*d)->save(record,false);
(*d)->save(record, false);
}
}
_listener->onNetworkMemberUpdate(this,networkId,memberId,member);
_listener->onNetworkMemberUpdate(this, networkId, memberId, member);
}
void DBMirrorSet::onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId)
void DBMirrorSet::onNetworkMemberDeauthorize(const void* db, uint64_t networkId, uint64_t memberId)
{
_listener->onNetworkMemberDeauthorize(this,networkId,memberId);
_listener->onNetworkMemberDeauthorize(this, networkId, memberId);
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -16,59 +16,58 @@
#include "DB.hpp"
#include <vector>
#include <memory>
#include <shared_mutex>
#include <set>
#include <shared_mutex>
#include <thread>
#include <vector>
namespace ZeroTier {
class DBMirrorSet : public DB::ChangeListener
{
public:
DBMirrorSet(DB::ChangeListener *listener);
class DBMirrorSet : public DB::ChangeListener {
public:
DBMirrorSet(DB::ChangeListener* listener);
virtual ~DBMirrorSet();
bool hasNetwork(const uint64_t networkId) const;
bool get(const uint64_t networkId,nlohmann::json &network);
bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member);
bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,DB::NetworkSummaryInfo &info);
bool get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members);
bool get(const uint64_t networkId, nlohmann::json& network);
bool get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member);
bool get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member, DB::NetworkSummaryInfo& info);
bool get(const uint64_t networkId, nlohmann::json& network, std::vector<nlohmann::json>& members);
void networks(std::set<uint64_t> &networks);
void networks(std::set<uint64_t>& networks);
bool waitForReady();
bool isReady();
bool save(nlohmann::json &record,bool notifyListeners);
bool save(nlohmann::json& record, bool notifyListeners);
void eraseNetwork(const uint64_t networkId);
void eraseMember(const uint64_t networkId,const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch);
void eraseMember(const uint64_t networkId, const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch);
// These are called by various DB instances when changes occur.
virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network);
virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member);
virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId);
virtual void onNetworkUpdate(const void* db, uint64_t networkId, const nlohmann::json& network);
virtual void onNetworkMemberUpdate(const void* db, uint64_t networkId, uint64_t memberId, const nlohmann::json& member);
virtual void onNetworkMemberDeauthorize(const void* db, uint64_t networkId, uint64_t memberId);
AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL);
AuthInfo getSSOAuthInfo(const nlohmann::json& member, const std::string& redirectURL);
inline void addDB(const std::shared_ptr<DB> &db)
inline void addDB(const std::shared_ptr<DB>& db)
{
db->addListener(this);
std::unique_lock<std::shared_mutex> l(_dbs_l);
_dbs.push_back(db);
}
private:
DB::ChangeListener *const _listener;
private:
DB::ChangeListener* const _listener;
std::atomic_bool _running;
std::thread _syncCheckerThread;
std::vector< std::shared_ptr< DB > > _dbs;
std::vector<std::shared_ptr<DB> > _dbs;
mutable std::shared_mutex _dbs_l;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,112 +14,109 @@
#ifndef ZT_SQLITENETWORKCONTROLLER_HPP
#define ZT_SQLITENETWORKCONTROLLER_HPP
#include <stdint.h>
#include <string>
#include <map>
#include <vector>
#include <set>
#include <list>
#include <thread>
#include <unordered_map>
#include <atomic>
#include "../node/Address.hpp"
#include "../node/Constants.hpp"
#include "../node/InetAddress.hpp"
#include "../node/NetworkController.hpp"
#include "../node/Utils.hpp"
#include "../node/Address.hpp"
#include "../node/InetAddress.hpp"
#include "../osdep/BlockingQueue.hpp"
#include "../osdep/OSUtils.hpp"
#include "../osdep/Thread.hpp"
#include "../osdep/BlockingQueue.hpp"
#include <nlohmann/json.hpp>
#include <cpp-httplib/httplib.h>
#include "DB.hpp"
#include "DBMirrorSet.hpp"
#include <atomic>
#include <cpp-httplib/httplib.h>
#include <list>
#include <map>
#include <nlohmann/json.hpp>
#include <set>
#include <stdint.h>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
namespace ZeroTier {
class Node;
struct RedisConfig;
class EmbeddedNetworkController : public NetworkController,public DB::ChangeListener
{
public:
class EmbeddedNetworkController
: public NetworkController
, public DB::ChangeListener {
public:
/**
* @param node Parent node
* @param dbPath Database path (file path or database credentials)
*/
EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, RedisConfig *rc);
EmbeddedNetworkController(Node* node, const char* ztPath, const char* dbPath, int listenPort, RedisConfig* rc);
virtual ~EmbeddedNetworkController();
virtual void init(const Identity &signingId,Sender *sender);
virtual void init(const Identity& signingId, Sender* sender);
void setSSORedirectURL(const std::string &url);
void setSSORedirectURL(const std::string& url);
virtual void request(
uint64_t nwid,
const InetAddress &fromAddr,
uint64_t requestPacketId,
const Identity &identity,
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
virtual void request(uint64_t nwid, const InetAddress& fromAddr, uint64_t requestPacketId, const Identity& identity, const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY>& metaData);
void configureHTTPControlPlane(
httplib::Server &s,
httplib::Server &sV6,
const std::function<void(const httplib::Request&, httplib::Response&, std::string)>);
void configureHTTPControlPlane(httplib::Server& s, httplib::Server& sV6, const std::function<void(const httplib::Request&, httplib::Response&, std::string)>);
void handleRemoteTrace(const ZT_RemoteTrace &rt);
void handleRemoteTrace(const ZT_RemoteTrace& rt);
virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network);
virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member);
virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId);
virtual void onNetworkUpdate(const void* db, uint64_t networkId, const nlohmann::json& network);
virtual void onNetworkMemberUpdate(const void* db, uint64_t networkId, uint64_t memberId, const nlohmann::json& member);
virtual void onNetworkMemberDeauthorize(const void* db, uint64_t networkId, uint64_t memberId);
private:
void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
private:
void _request(uint64_t nwid, const InetAddress& fromAddr, uint64_t requestPacketId, const Identity& identity, const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY>& metaData);
void _startThreads();
void _ssoExpiryThread();
std::string networkUpdateFromPostData(uint64_t networkID, const std::string &body);
std::string networkUpdateFromPostData(uint64_t networkID, const std::string& body);
struct _RQEntry
{
struct _RQEntry {
uint64_t nwid;
uint64_t requestPacketId;
InetAddress fromAddr;
Identity identity;
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> metaData;
enum {
RQENTRY_TYPE_REQUEST = 0
} type;
enum { RQENTRY_TYPE_REQUEST = 0 } type;
};
struct _MemberStatusKey
{
_MemberStatusKey() : networkId(0),nodeId(0) {}
_MemberStatusKey(const uint64_t nwid,const uint64_t nid) : networkId(nwid),nodeId(nid) {}
struct _MemberStatusKey {
_MemberStatusKey() : networkId(0), nodeId(0)
{
}
_MemberStatusKey(const uint64_t nwid, const uint64_t nid) : networkId(nwid), nodeId(nid)
{
}
uint64_t networkId;
uint64_t nodeId;
inline bool operator==(const _MemberStatusKey &k) const { return ((k.networkId == networkId)&&(k.nodeId == nodeId)); }
inline bool operator<(const _MemberStatusKey &k) const { return (k.networkId < networkId) || ((k.networkId == networkId)&&(k.nodeId < nodeId)); }
inline bool operator==(const _MemberStatusKey& k) const
{
return ((k.networkId == networkId) && (k.nodeId == nodeId));
}
inline bool operator<(const _MemberStatusKey& k) const
{
return (k.networkId < networkId) || ((k.networkId == networkId) && (k.nodeId < nodeId));
}
};
struct _MemberStatus
{
_MemberStatus() : lastRequestTime(0),authenticationExpiryTime(-1),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {}
struct _MemberStatus {
_MemberStatus() : lastRequestTime(0), authenticationExpiryTime(-1), vMajor(-1), vMinor(-1), vRev(-1), vProto(-1)
{
}
int64_t lastRequestTime;
int64_t authenticationExpiryTime;
int vMajor,vMinor,vRev,vProto;
int vMajor, vMinor, vRev, vProto;
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> lastRequestMetaData;
Identity identity;
inline bool online(const int64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); }
inline bool online(const int64_t now) const
{
return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2));
}
};
struct _MemberStatusHash
{
inline std::size_t operator()(const _MemberStatusKey &networkIdNodeId) const
struct _MemberStatusHash {
inline std::size_t operator()(const _MemberStatusKey& networkIdNodeId) const
{
return (std::size_t)(networkIdNodeId.networkId + networkIdNodeId.nodeId);
}
@ -127,26 +124,26 @@ private:
const int64_t _startTime;
int _listenPort;
Node *const _node;
Node* const _node;
std::string _ztPath;
std::string _path;
Identity _signingId;
std::string _signingIdAddressString;
NetworkController::Sender *_sender;
NetworkController::Sender* _sender;
DBMirrorSet _db;
BlockingQueue< _RQEntry * > _queue;
BlockingQueue<_RQEntry*> _queue;
std::vector<std::thread> _threads;
std::mutex _threads_l;
std::unordered_map< _MemberStatusKey,_MemberStatus,_MemberStatusHash > _memberStatus;
std::unordered_map<_MemberStatusKey, _MemberStatus, _MemberStatusHash> _memberStatus;
std::mutex _memberStatus_l;
std::set< std::pair<int64_t, _MemberStatusKey> > _expiringSoon;
std::set<std::pair<int64_t, _MemberStatusKey> > _expiringSoon;
std::mutex _expiringSoon_l;
RedisConfig *_rc;
RedisConfig* _rc;
std::string _ssoRedirectURL;
bool _ssoExpiryRunning;
@ -154,30 +151,30 @@ private:
#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK
prometheus::simpleapi::benchmark_family_t _member_status_lookup;
prometheus::simpleapi::counter_family_t _member_status_lookup_count;
prometheus::simpleapi::counter_family_t _member_status_lookup_count;
prometheus::simpleapi::benchmark_family_t _node_is_online;
prometheus::simpleapi::counter_family_t _node_is_online_count;
prometheus::simpleapi::counter_family_t _node_is_online_count;
prometheus::simpleapi::benchmark_family_t _get_and_init_member;
prometheus::simpleapi::counter_family_t _get_and_init_member_count;
prometheus::simpleapi::counter_family_t _get_and_init_member_count;
prometheus::simpleapi::benchmark_family_t _have_identity;
prometheus::simpleapi::counter_family_t _have_identity_count;
prometheus::simpleapi::counter_family_t _have_identity_count;
prometheus::simpleapi::benchmark_family_t _determine_auth;
prometheus::simpleapi::counter_family_t _determine_auth_count;
prometheus::simpleapi::counter_family_t _determine_auth_count;
prometheus::simpleapi::benchmark_family_t _sso_check;
prometheus::simpleapi::counter_family_t _sso_check_count;
prometheus::simpleapi::counter_family_t _sso_check_count;
prometheus::simpleapi::benchmark_family_t _auth_check;
prometheus::simpleapi::counter_family_t _auth_check_count;
prometheus::simpleapi::counter_family_t _auth_check_count;
prometheus::simpleapi::benchmark_family_t _json_schlep;
prometheus::simpleapi::counter_family_t _json_schlep_count;
prometheus::simpleapi::counter_family_t _json_schlep_count;
prometheus::simpleapi::benchmark_family_t _issue_certificate;
prometheus::simpleapi::counter_family_t _issue_certificate_count;
prometheus::simpleapi::counter_family_t _issue_certificate_count;
prometheus::simpleapi::benchmark_family_t _save_member;
prometheus::simpleapi::counter_family_t _save_member_count;
prometheus::simpleapi::counter_family_t _save_member_count;
prometheus::simpleapi::benchmark_family_t _send_netconf;
prometheus::simpleapi::counter_family_t _send_netconf_count;
prometheus::simpleapi::counter_family_t _send_netconf_count;
#endif
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -15,51 +15,49 @@
#include "../node/Metrics.hpp"
namespace ZeroTier
{
namespace ZeroTier {
FileDB::FileDB(const char *path) :
DB(),
_path(path),
_networksPath(_path + ZT_PATH_SEPARATOR_S + "network"),
_tracePath(_path + ZT_PATH_SEPARATOR_S + "trace"),
_running(true)
FileDB::FileDB(const char* path) : DB(), _path(path), _networksPath(_path + ZT_PATH_SEPARATOR_S + "network"), _tracePath(_path + ZT_PATH_SEPARATOR_S + "trace"), _running(true)
{
OSUtils::mkdir(_path.c_str());
OSUtils::lockDownFile(_path.c_str(),true);
OSUtils::lockDownFile(_path.c_str(), true);
OSUtils::mkdir(_networksPath.c_str());
OSUtils::mkdir(_tracePath.c_str());
std::vector<std::string> networks(OSUtils::listDirectory(_networksPath.c_str(),false));
std::vector<std::string> networks(OSUtils::listDirectory(_networksPath.c_str(), false));
std::string buf;
for(auto n=networks.begin();n!=networks.end();++n) {
for (auto n = networks.begin(); n != networks.end(); ++n) {
buf.clear();
if ((n->length() == 21)&&(OSUtils::readFile((_networksPath + ZT_PATH_SEPARATOR_S + *n).c_str(),buf))) {
if ((n->length() == 21) && (OSUtils::readFile((_networksPath + ZT_PATH_SEPARATOR_S + *n).c_str(), buf))) {
try {
nlohmann::json network(OSUtils::jsonParse(buf));
const std::string nwids = network["id"];
if (nwids.length() == 16) {
nlohmann::json nullJson;
_networkChanged(nullJson,network,false);
_networkChanged(nullJson, network, false);
Metrics::network_count++;
std::string membersPath(_networksPath + ZT_PATH_SEPARATOR_S + nwids + ZT_PATH_SEPARATOR_S "member");
std::vector<std::string> members(OSUtils::listDirectory(membersPath.c_str(),false));
for(auto m=members.begin();m!=members.end();++m) {
std::vector<std::string> members(OSUtils::listDirectory(membersPath.c_str(), false));
for (auto m = members.begin(); m != members.end(); ++m) {
buf.clear();
if ((m->length() == 15)&&(OSUtils::readFile((membersPath + ZT_PATH_SEPARATOR_S + *m).c_str(),buf))) {
if ((m->length() == 15) && (OSUtils::readFile((membersPath + ZT_PATH_SEPARATOR_S + *m).c_str(), buf))) {
try {
nlohmann::json member(OSUtils::jsonParse(buf));
const std::string addrs = member["id"];
if (addrs.length() == 10) {
nlohmann::json nullJson2;
_memberChanged(nullJson2,member,false);
_memberChanged(nullJson2, member, false);
Metrics::member_count++;
}
} catch ( ... ) {}
}
catch (...) {
}
}
}
}
} catch ( ... ) {}
}
catch (...) {
}
}
}
}
@ -71,101 +69,109 @@ FileDB::~FileDB()
_running = false;
_online_l.unlock();
_onlineUpdateThread.join();
} catch ( ... ) {}
}
catch (...) {
}
}
bool FileDB::waitForReady() { return true; }
bool FileDB::isReady() { return true; }
bool FileDB::save(nlohmann::json &record,bool notifyListeners)
bool FileDB::waitForReady()
{
char p1[4096],p2[4096],pb[4096];
return true;
}
bool FileDB::isReady()
{
return true;
}
bool FileDB::save(nlohmann::json& record, bool notifyListeners)
{
char p1[4096], p2[4096], pb[4096];
bool modified = false;
try {
const std::string objtype = record["objtype"];
if (objtype == "network") {
const uint64_t nwid = OSUtils::jsonIntHex(record["id"],0ULL);
const uint64_t nwid = OSUtils::jsonIntHex(record["id"], 0ULL);
if (nwid) {
nlohmann::json old;
get(nwid,old);
if ((!old.is_object())||(!_compareRecords(old,record))) {
record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL;
OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),nwid);
if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) {
fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1);
get(nwid, old);
if ((! old.is_object()) || (! _compareRecords(old, record))) {
record["revision"] = OSUtils::jsonInt(record["revision"], 0ULL) + 1ULL;
OSUtils::ztsnprintf(p1, sizeof(p1), "%s" ZT_PATH_SEPARATOR_S "%.16llx.json", _networksPath.c_str(), nwid);
if (! OSUtils::writeFile(p1, OSUtils::jsonDump(record, -1))) {
fprintf(stderr, "WARNING: controller unable to write to path: %s" ZT_EOL_S, p1);
}
_networkChanged(old,record,notifyListeners);
_networkChanged(old, record, notifyListeners);
modified = true;
}
}
} else if (objtype == "member") {
const uint64_t id = OSUtils::jsonIntHex(record["id"],0ULL);
const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"],0ULL);
if ((id)&&(nwid)) {
nlohmann::json network,old;
get(nwid,network,id,old);
if ((!old.is_object())||(!_compareRecords(old,record))) {
record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL;
OSUtils::ztsnprintf(pb,sizeof(pb),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member",_networksPath.c_str(),(unsigned long long)nwid);
OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%.10llx.json",pb,(unsigned long long)id);
if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) {
OSUtils::ztsnprintf(p2,sizeof(p2),"%s" ZT_PATH_SEPARATOR_S "%.16llx",_networksPath.c_str(),(unsigned long long)nwid);
}
else if (objtype == "member") {
const uint64_t id = OSUtils::jsonIntHex(record["id"], 0ULL);
const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"], 0ULL);
if ((id) && (nwid)) {
nlohmann::json network, old;
get(nwid, network, id, old);
if ((! old.is_object()) || (! _compareRecords(old, record))) {
record["revision"] = OSUtils::jsonInt(record["revision"], 0ULL) + 1ULL;
OSUtils::ztsnprintf(pb, sizeof(pb), "%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member", _networksPath.c_str(), (unsigned long long)nwid);
OSUtils::ztsnprintf(p1, sizeof(p1), "%s" ZT_PATH_SEPARATOR_S "%.10llx.json", pb, (unsigned long long)id);
if (! OSUtils::writeFile(p1, OSUtils::jsonDump(record, -1))) {
OSUtils::ztsnprintf(p2, sizeof(p2), "%s" ZT_PATH_SEPARATOR_S "%.16llx", _networksPath.c_str(), (unsigned long long)nwid);
OSUtils::mkdir(p2);
OSUtils::mkdir(pb);
if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) {
fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1);
if (! OSUtils::writeFile(p1, OSUtils::jsonDump(record, -1))) {
fprintf(stderr, "WARNING: controller unable to write to path: %s" ZT_EOL_S, p1);
}
}
_memberChanged(old,record,notifyListeners);
_memberChanged(old, record, notifyListeners);
modified = true;
}
}
}
} catch ( ... ) {} // drop invalid records missing fields
}
catch (...) {
} // drop invalid records missing fields
return modified;
}
void FileDB::eraseNetwork(const uint64_t networkId)
{
nlohmann::json network,nullJson;
get(networkId,network);
nlohmann::json network, nullJson;
get(networkId, network);
char p[16384];
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),networkId);
OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "%.16llx.json", _networksPath.c_str(), networkId);
OSUtils::rm(p);
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx",_networksPath.c_str(),(unsigned long long)networkId);
OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "%.16llx", _networksPath.c_str(), (unsigned long long)networkId);
OSUtils::rmDashRf(p);
_networkChanged(network,nullJson,true);
_networkChanged(network, nullJson, true);
std::lock_guard<std::mutex> l(this->_online_l);
this->_online.erase(networkId);
}
void FileDB::eraseMember(const uint64_t networkId,const uint64_t memberId)
void FileDB::eraseMember(const uint64_t networkId, const uint64_t memberId)
{
nlohmann::json network,member,nullJson;
get(networkId,network,memberId,member);
nlohmann::json network, member, nullJson;
get(networkId, network, memberId, member);
char p[4096];
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member" ZT_PATH_SEPARATOR_S "%.10llx.json",_networksPath.c_str(),networkId,memberId);
OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member" ZT_PATH_SEPARATOR_S "%.10llx.json", _networksPath.c_str(), networkId, memberId);
OSUtils::rm(p);
_memberChanged(member,nullJson,true);
_memberChanged(member, nullJson, true);
std::lock_guard<std::mutex> l(this->_online_l);
this->_online[networkId].erase(memberId);
}
void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch) {
char mid[32],atmp[64];
OSUtils::ztsnprintf(mid,sizeof(mid),"%.10llx",(unsigned long long)memberId);
void FileDB::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch)
{
char mid[32], atmp[64];
OSUtils::ztsnprintf(mid, sizeof(mid), "%.10llx", (unsigned long long)memberId);
physicalAddress.toString(atmp);
std::lock_guard<std::mutex> l(this->_online_l);
this->_online[networkId][memberId][OSUtils::now()] = physicalAddress;
}
void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
void FileDB::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress)
{
this->nodeIsOnline(networkId,memberId,physicalAddress,"unknown/unknown");
this->nodeIsOnline(networkId, memberId, physicalAddress, "unknown/unknown");
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -16,33 +16,31 @@
#include "DB.hpp"
namespace ZeroTier
{
namespace ZeroTier {
class FileDB : public DB
{
public:
FileDB(const char *path);
class FileDB : public DB {
public:
FileDB(const char* path);
virtual ~FileDB();
virtual bool waitForReady();
virtual bool isReady();
virtual bool save(nlohmann::json &record,bool notifyListeners);
virtual bool save(nlohmann::json& record, bool notifyListeners);
virtual void eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch);
protected:
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch);
protected:
std::string _path;
std::string _networksPath;
std::string _tracePath;
std::thread _onlineUpdateThread;
std::map< uint64_t,std::map<uint64_t,std::map<int64_t,InetAddress> > > _online;
std::map<uint64_t, std::map<uint64_t, std::map<int64_t, InetAddress> > > _online;
std::mutex _online_l;
bool _running;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -13,51 +13,52 @@
#include "LFDB.hpp"
#include <thread>
#include "../ext/cpp-httplib/httplib.h"
#include "../osdep/OSUtils.hpp"
#include <chrono>
#include <iostream>
#include <sstream>
#include <thread>
#include "../osdep/OSUtils.hpp"
#include "../ext/cpp-httplib/httplib.h"
namespace ZeroTier {
namespace ZeroTier
{
LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,const char *lfOwnerPublic,const char *lfNodeHost,int lfNodePort,bool storeOnlineState) :
DB(),
_myId(myId),
_lfOwnerPrivate((lfOwnerPrivate) ? lfOwnerPrivate : ""),
_lfOwnerPublic((lfOwnerPublic) ? lfOwnerPublic : ""),
_lfNodeHost((lfNodeHost) ? lfNodeHost : "127.0.0.1"),
_lfNodePort(((lfNodePort > 0)&&(lfNodePort < 65536)) ? lfNodePort : 9980),
_running(true),
_ready(false),
_storeOnlineState(storeOnlineState)
LFDB::LFDB(const Identity& myId, const char* path, const char* lfOwnerPrivate, const char* lfOwnerPublic, const char* lfNodeHost, int lfNodePort, bool storeOnlineState)
: DB()
, _myId(myId)
, _lfOwnerPrivate((lfOwnerPrivate) ? lfOwnerPrivate : "")
, _lfOwnerPublic((lfOwnerPublic) ? lfOwnerPublic : "")
, _lfNodeHost((lfNodeHost) ? lfNodeHost : "127.0.0.1")
, _lfNodePort(((lfNodePort > 0) && (lfNodePort < 65536)) ? lfNodePort : 9980)
, _running(true)
, _ready(false)
, _storeOnlineState(storeOnlineState)
{
_syncThread = std::thread([this]() {
char controllerAddress[24];
const uint64_t controllerAddressInt = _myId.address().toInt();
_myId.address().toString(controllerAddress);
std::string networksSelectorName("com.zerotier.controller.lfdb:"); networksSelectorName.append(controllerAddress); networksSelectorName.append("/network");
std::string networksSelectorName("com.zerotier.controller.lfdb:");
networksSelectorName.append(controllerAddress);
networksSelectorName.append("/network");
// LF record masking key is the first 32 bytes of SHA512(controller private key) in hex,
// hiding record values from anything but the controller or someone who has its key.
uint8_t sha512pk[64];
_myId.sha512PrivateKey(sha512pk);
char maskingKey [128];
Utils::hex(sha512pk,32,maskingKey);
char maskingKey[128];
Utils::hex(sha512pk, 32, maskingKey);
httplib::Client htcli(_lfNodeHost.c_str(),_lfNodePort);
httplib::Client htcli(_lfNodeHost.c_str(), _lfNodePort);
int64_t timeRangeStart = 0;
while (_running.load()) {
{
std::lock_guard<std::mutex> sl(_state_l);
for(auto ns=_state.begin();ns!=_state.end();++ns) {
for (auto ns = _state.begin(); ns != _state.end(); ++ns) {
if (ns->second.dirty) {
nlohmann::json network;
if (get(ns->first,network)) {
nlohmann::json newrec,selector0;
if (get(ns->first, network)) {
nlohmann::json newrec, selector0;
selector0["Name"] = networksSelectorName;
selector0["Ordinal"] = ns->first;
newrec["Selectors"].push_back(selector0);
@ -66,30 +67,34 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
newrec["MaskingKey"] = maskingKey;
newrec["PulseIfUnchanged"] = true;
try {
auto resp = htcli.Post("/makerecord",newrec.dump(),"application/json");
auto resp = htcli.Post("/makerecord", newrec.dump(), "application/json");
if (resp) {
if (resp->status == 200) {
ns->second.dirty = false;
//printf("SET network %.16llx %s\n",ns->first,resp->body.c_str());
} else {
fprintf(stderr,"ERROR: LFDB: %d from node (create/update network): %s" ZT_EOL_S,resp->status,resp->body.c_str());
// printf("SET network %.16llx %s\n",ns->first,resp->body.c_str());
}
else {
fprintf(stderr, "ERROR: LFDB: %d from node (create/update network): %s" ZT_EOL_S, resp->status, resp->body.c_str());
}
} else {
fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S);
}
} catch (std::exception &e) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update network): %s" ZT_EOL_S,e.what());
} catch ( ... ) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update network): unknown exception" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: node is offline" ZT_EOL_S);
}
}
catch (std::exception& e) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update network): %s" ZT_EOL_S, e.what());
}
catch (...) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update network): unknown exception" ZT_EOL_S);
}
}
}
for(auto ms=ns->second.members.begin();ms!=ns->second.members.end();++ms) {
if ((_storeOnlineState)&&(ms->second.lastOnlineDirty)&&(ms->second.lastOnlineAddress)) {
nlohmann::json newrec,selector0,selector1,selectors,ip;
char tmp[1024],tmp2[128];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"com.zerotier.controller.lfdb:%s/network/%.16llx/online",controllerAddress,(unsigned long long)ns->first);
for (auto ms = ns->second.members.begin(); ms != ns->second.members.end(); ++ms) {
if ((_storeOnlineState) && (ms->second.lastOnlineDirty) && (ms->second.lastOnlineAddress)) {
nlohmann::json newrec, selector0, selector1, selectors, ip;
char tmp[1024], tmp2[128];
OSUtils::ztsnprintf(tmp, sizeof(tmp), "com.zerotier.controller.lfdb:%s/network/%.16llx/online", controllerAddress, (unsigned long long)ns->first);
ms->second.lastOnlineAddress.toIpString(tmp2);
selector0["Name"] = tmp;
selector0["Ordinal"] = ms->first;
@ -98,18 +103,18 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
selectors.push_back(selector0);
selectors.push_back(selector1);
newrec["Selectors"] = selectors;
const uint8_t *const rawip = (const uint8_t *)ms->second.lastOnlineAddress.rawIpData();
switch(ms->second.lastOnlineAddress.ss_family) {
const uint8_t* const rawip = (const uint8_t*)ms->second.lastOnlineAddress.rawIpData();
switch (ms->second.lastOnlineAddress.ss_family) {
case AF_INET:
for(int j=0;j<4;++j)
for (int j = 0; j < 4; ++j)
ip.push_back((unsigned int)rawip[j]);
break;
case AF_INET6:
for(int j=0;j<16;++j)
for (int j = 0; j < 16; ++j)
ip.push_back((unsigned int)rawip[j]);
break;
default:
ip = tmp2; // should never happen since only IP transport is currently supported
ip = tmp2; // should never happen since only IP transport is currently supported
break;
}
newrec["Value"] = ip;
@ -118,28 +123,32 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
newrec["Timestamp"] = ms->second.lastOnlineTime;
newrec["PulseIfUnchanged"] = true;
try {
auto resp = htcli.Post("/makerecord",newrec.dump(),"application/json");
auto resp = htcli.Post("/makerecord", newrec.dump(), "application/json");
if (resp) {
if (resp->status == 200) {
ms->second.lastOnlineDirty = false;
//printf("SET member online %.16llx %.10llx %s\n",ns->first,ms->first,resp->body.c_str());
} else {
fprintf(stderr,"ERROR: LFDB: %d from node (create/update member online status): %s" ZT_EOL_S,resp->status,resp->body.c_str());
// printf("SET member online %.16llx %.10llx %s\n",ns->first,ms->first,resp->body.c_str());
}
else {
fprintf(stderr, "ERROR: LFDB: %d from node (create/update member online status): %s" ZT_EOL_S, resp->status, resp->body.c_str());
}
} else {
fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S);
}
} catch (std::exception &e) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member online status): %s" ZT_EOL_S,e.what());
} catch ( ... ) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member online status): unknown exception" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: node is offline" ZT_EOL_S);
}
}
catch (std::exception& e) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update member online status): %s" ZT_EOL_S, e.what());
}
catch (...) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update member online status): unknown exception" ZT_EOL_S);
}
}
if (ms->second.dirty) {
nlohmann::json network,member;
if (get(ns->first,network,ms->first,member)) {
nlohmann::json newrec,selector0,selector1,selectors;
nlohmann::json network, member;
if (get(ns->first, network, ms->first, member)) {
nlohmann::json newrec, selector0, selector1, selectors;
selector0["Name"] = networksSelectorName;
selector0["Ordinal"] = ns->first;
selector1["Name"] = "member";
@ -152,21 +161,25 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
newrec["MaskingKey"] = maskingKey;
newrec["PulseIfUnchanged"] = true;
try {
auto resp = htcli.Post("/makerecord",newrec.dump(),"application/json");
auto resp = htcli.Post("/makerecord", newrec.dump(), "application/json");
if (resp) {
if (resp->status == 200) {
ms->second.dirty = false;
//printf("SET member %.16llx %.10llx %s\n",ns->first,ms->first,resp->body.c_str());
} else {
fprintf(stderr,"ERROR: LFDB: %d from node (create/update member): %s" ZT_EOL_S,resp->status,resp->body.c_str());
// printf("SET member %.16llx %.10llx %s\n",ns->first,ms->first,resp->body.c_str());
}
else {
fprintf(stderr, "ERROR: LFDB: %d from node (create/update member): %s" ZT_EOL_S, resp->status, resp->body.c_str());
}
} else {
fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S);
}
} catch (std::exception &e) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member): %s" ZT_EOL_S,e.what());
} catch ( ... ) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member): unknown exception" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: node is offline" ZT_EOL_S);
}
}
catch (std::exception& e) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update member): %s" ZT_EOL_S, e.what());
}
catch (...) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update member): unknown exception" ZT_EOL_S);
}
}
}
@ -176,143 +189,161 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
try {
std::ostringstream query;
query <<
"{"
"\"Ranges\":[{"
"\"Name\":\"" << networksSelectorName << "\","
"\"Range\":[0,18446744073709551615]"
"}],"
"\"TimeRange\":[" << timeRangeStart << ",9223372036854775807],"
"\"MaskingKey\":\"" << maskingKey << "\","
"\"Owners\":[\"" << _lfOwnerPublic << "\"]"
"}";
auto resp = htcli.Post("/query",query.str(),"application/json");
query << "{"
"\"Ranges\":[{"
"\"Name\":\""
<< networksSelectorName
<< "\","
"\"Range\":[0,18446744073709551615]"
"}],"
"\"TimeRange\":["
<< timeRangeStart
<< ",9223372036854775807],"
"\"MaskingKey\":\""
<< maskingKey
<< "\","
"\"Owners\":[\""
<< _lfOwnerPublic
<< "\"]"
"}";
auto resp = htcli.Post("/query", query.str(), "application/json");
if (resp) {
if (resp->status == 200) {
nlohmann::json results(OSUtils::jsonParse(resp->body));
if ((results.is_array())&&(!results.empty())) {
for(std::size_t ri=0;ri<results.size();++ri) {
nlohmann::json &rset = results[ri];
if ((rset.is_array())&&(!rset.empty())) {
nlohmann::json &result = rset[0];
if ((results.is_array()) && (! results.empty())) {
for (std::size_t ri = 0; ri < results.size(); ++ri) {
nlohmann::json& rset = results[ri];
if ((rset.is_array()) && (! rset.empty())) {
nlohmann::json& result = rset[0];
if (result.is_object()) {
nlohmann::json &record = result["Record"];
nlohmann::json& record = result["Record"];
if (record.is_object()) {
const std::string recordValue = result["Value"];
//printf("GET network %s\n",recordValue.c_str());
// printf("GET network %s\n",recordValue.c_str());
nlohmann::json network(OSUtils::jsonParse(recordValue));
if (network.is_object()) {
const std::string idstr = network["id"];
const uint64_t id = Utils::hexStrToU64(idstr.c_str());
if ((id >> 24) == controllerAddressInt) { // sanity check
if ((id >> 24) == controllerAddressInt) { // sanity check
nlohmann::json oldNetwork;
if ((timeRangeStart > 0)&&(get(id,oldNetwork))) {
if ((timeRangeStart > 0) && (get(id, oldNetwork))) {
const uint64_t revision = network["revision"];
const uint64_t prevRevision = oldNetwork["revision"];
if (prevRevision < revision) {
_networkChanged(oldNetwork,network,timeRangeStart > 0);
_networkChanged(oldNetwork, network, timeRangeStart > 0);
}
} else {
nlohmann::json nullJson;
_networkChanged(nullJson,network,timeRangeStart > 0);
}
else {
nlohmann::json nullJson;
_networkChanged(nullJson, network, timeRangeStart > 0);
}
}
}
}
}
}
}
}
} else {
fprintf(stderr,"ERROR: LFDB: %d from node (check for network updates): %s" ZT_EOL_S,resp->status,resp->body.c_str());
}
} else {
fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: %d from node (check for network updates): %s" ZT_EOL_S, resp->status, resp->body.c_str());
}
}
} catch (std::exception &e) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for network updates): %s" ZT_EOL_S,e.what());
} catch ( ... ) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for network updates): unknown exception" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: node is offline" ZT_EOL_S);
}
}
catch (std::exception& e) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (check for network updates): %s" ZT_EOL_S, e.what());
}
catch (...) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (check for network updates): unknown exception" ZT_EOL_S);
}
try {
std::ostringstream query;
query <<
"{"
"\"Ranges\":[{"
"\"Name\":\"" << networksSelectorName << "\","
"\"Range\":[0,18446744073709551615]"
"},{"
"\"Name\":\"member\","
"\"Range\":[0,18446744073709551615]"
"}],"
"\"TimeRange\":[" << timeRangeStart << ",9223372036854775807],"
"\"MaskingKey\":\"" << maskingKey << "\","
"\"Owners\":[\"" << _lfOwnerPublic << "\"]"
"}";
auto resp = htcli.Post("/query",query.str(),"application/json");
query << "{"
"\"Ranges\":[{"
"\"Name\":\""
<< networksSelectorName
<< "\","
"\"Range\":[0,18446744073709551615]"
"},{"
"\"Name\":\"member\","
"\"Range\":[0,18446744073709551615]"
"}],"
"\"TimeRange\":["
<< timeRangeStart
<< ",9223372036854775807],"
"\"MaskingKey\":\""
<< maskingKey
<< "\","
"\"Owners\":[\""
<< _lfOwnerPublic
<< "\"]"
"}";
auto resp = htcli.Post("/query", query.str(), "application/json");
if (resp) {
if (resp->status == 200) {
nlohmann::json results(OSUtils::jsonParse(resp->body));
if ((results.is_array())&&(!results.empty())) {
for(std::size_t ri=0;ri<results.size();++ri) {
nlohmann::json &rset = results[ri];
if ((rset.is_array())&&(!rset.empty())) {
nlohmann::json &result = rset[0];
if ((results.is_array()) && (! results.empty())) {
for (std::size_t ri = 0; ri < results.size(); ++ri) {
nlohmann::json& rset = results[ri];
if ((rset.is_array()) && (! rset.empty())) {
nlohmann::json& result = rset[0];
if (result.is_object()) {
nlohmann::json &record = result["Record"];
nlohmann::json& record = result["Record"];
if (record.is_object()) {
const std::string recordValue = result["Value"];
//printf("GET member %s\n",recordValue.c_str());
// printf("GET member %s\n",recordValue.c_str());
nlohmann::json member(OSUtils::jsonParse(recordValue));
if (member.is_object()) {
const std::string nwidstr = member["nwid"];
const std::string idstr = member["id"];
const uint64_t nwid = Utils::hexStrToU64(nwidstr.c_str());
const uint64_t id = Utils::hexStrToU64(idstr.c_str());
if ((id)&&((nwid >> 24) == controllerAddressInt)) { // sanity check
if ((id) && ((nwid >> 24) == controllerAddressInt)) { // sanity check
nlohmann::json network,oldMember;
if ((timeRangeStart > 0)&&(get(nwid,network,id,oldMember))) {
nlohmann::json network, oldMember;
if ((timeRangeStart > 0) && (get(nwid, network, id, oldMember))) {
const uint64_t revision = member["revision"];
const uint64_t prevRevision = oldMember["revision"];
if (prevRevision < revision)
_memberChanged(oldMember,member,timeRangeStart > 0);
} else if (hasNetwork(nwid)) {
nlohmann::json nullJson;
_memberChanged(nullJson,member,timeRangeStart > 0);
_memberChanged(oldMember, member, timeRangeStart > 0);
}
else if (hasNetwork(nwid)) {
nlohmann::json nullJson;
_memberChanged(nullJson, member, timeRangeStart > 0);
}
}
}
}
}
}
}
}
} else {
fprintf(stderr,"ERROR: LFDB: %d from node (check for member updates): %s" ZT_EOL_S,resp->status,resp->body.c_str());
}
} else {
fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: %d from node (check for member updates): %s" ZT_EOL_S, resp->status, resp->body.c_str());
}
}
} catch (std::exception &e) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for member updates): %s" ZT_EOL_S,e.what());
} catch ( ... ) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for member updates): unknown exception" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: node is offline" ZT_EOL_S);
}
}
catch (std::exception& e) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (check for member updates): %s" ZT_EOL_S, e.what());
}
catch (...) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (check for member updates): unknown exception" ZT_EOL_S);
}
timeRangeStart = time(nullptr) - 120; // start next query 2m before now to avoid losing updates
timeRangeStart = time(nullptr) - 120; // start next query 2m before now to avoid losing updates
_ready.store(true);
for(int k=0;k<4;++k) { // 2s delay between queries for remotely modified networks or members
if (!_running.load())
for (int k = 0; k < 4; ++k) { // 2s delay between queries for remotely modified networks or members
if (! _running.load())
return;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
@ -328,7 +359,7 @@ LFDB::~LFDB()
bool LFDB::waitForReady()
{
while (!_ready.load()) {
while (! _ready.load()) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
return true;
@ -339,18 +370,18 @@ bool LFDB::isReady()
return (_ready.load());
}
bool LFDB::save(nlohmann::json &record,bool notifyListeners)
bool LFDB::save(nlohmann::json& record, bool notifyListeners)
{
bool modified = false;
const std::string objtype = record["objtype"];
if (objtype == "network") {
const uint64_t nwid = OSUtils::jsonIntHex(record["id"],0ULL);
const uint64_t nwid = OSUtils::jsonIntHex(record["id"], 0ULL);
if (nwid) {
nlohmann::json old;
get(nwid,old);
if ((!old.is_object())||(!_compareRecords(old,record))) {
record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL;
_networkChanged(old,record,notifyListeners);
get(nwid, old);
if ((! old.is_object()) || (! _compareRecords(old, record))) {
record["revision"] = OSUtils::jsonInt(record["revision"], 0ULL) + 1ULL;
_networkChanged(old, record, notifyListeners);
{
std::lock_guard<std::mutex> l(_state_l);
_state[nwid].dirty = true;
@ -358,15 +389,16 @@ bool LFDB::save(nlohmann::json &record,bool notifyListeners)
modified = true;
}
}
} else if (objtype == "member") {
const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"],0ULL);
const uint64_t id = OSUtils::jsonIntHex(record["id"],0ULL);
if ((id)&&(nwid)) {
nlohmann::json network,old;
get(nwid,network,id,old);
if ((!old.is_object())||(!_compareRecords(old,record))) {
record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL;
_memberChanged(old,record,notifyListeners);
}
else if (objtype == "member") {
const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"], 0ULL);
const uint64_t id = OSUtils::jsonIntHex(record["id"], 0ULL);
if ((id) && (nwid)) {
nlohmann::json network, old;
get(nwid, network, id, old);
if ((! old.is_object()) || (! _compareRecords(old, record))) {
record["revision"] = OSUtils::jsonInt(record["revision"], 0ULL) + 1ULL;
_memberChanged(old, record, notifyListeners);
{
std::lock_guard<std::mutex> l(_state_l);
_state[nwid].members[id].dirty = true;
@ -383,12 +415,12 @@ void LFDB::eraseNetwork(const uint64_t networkId)
// TODO
}
void LFDB::eraseMember(const uint64_t networkId,const uint64_t memberId)
void LFDB::eraseMember(const uint64_t networkId, const uint64_t memberId)
{
// TODO
}
void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress,const char *osArch)
void LFDB::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch)
{
std::lock_guard<std::mutex> l(_state_l);
auto nw = _state.find(networkId);
@ -403,9 +435,9 @@ void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const I
}
}
void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
void LFDB::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress)
{
this->nodeIsOnline(networkId,memberId,physicalAddress,"unknown/unknown");
this->nodeIsOnline(networkId, memberId, physicalAddress, "unknown/unknown");
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -16,19 +16,18 @@
#include "DB.hpp"
#include <atomic>
#include <mutex>
#include <string>
#include <unordered_map>
#include <atomic>
namespace ZeroTier {
/**
* DB implementation for controller that stores data in LF
*/
class LFDB : public DB
{
public:
class LFDB : public DB {
public:
/**
* @param myId This controller's identity
* @param path Base path for ZeroTier node itself
@ -38,45 +37,41 @@ public:
* @param lfNodePort LF node http (not https) port
* @param storeOnlineState If true, store online/offline state and IP info in LF (a lot of data, only for private networks!)
*/
LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,const char *lfOwnerPublic,const char *lfNodeHost,int lfNodePort,bool storeOnlineState);
LFDB(const Identity& myId, const char* path, const char* lfOwnerPrivate, const char* lfOwnerPublic, const char* lfNodeHost, int lfNodePort, bool storeOnlineState);
virtual ~LFDB();
virtual bool waitForReady();
virtual bool isReady();
virtual bool save(nlohmann::json &record,bool notifyListeners);
virtual bool save(nlohmann::json& record, bool notifyListeners);
virtual void eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch);
protected:
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch);
protected:
const Identity _myId;
std::string _lfOwnerPrivate,_lfOwnerPublic;
std::string _lfOwnerPrivate, _lfOwnerPublic;
std::string _lfNodeHost;
int _lfNodePort;
struct _MemberState
{
_MemberState() :
lastOnlineAddress(),
lastOnlineTime(0),
dirty(false),
lastOnlineDirty(false) {}
struct _MemberState {
_MemberState() : lastOnlineAddress(), lastOnlineTime(0), dirty(false), lastOnlineDirty(false)
{
}
InetAddress lastOnlineAddress;
int64_t lastOnlineTime;
bool dirty;
bool lastOnlineDirty;
};
struct _NetworkState
{
_NetworkState() :
members(),
dirty(false) {}
std::unordered_map<uint64_t,_MemberState> members;
struct _NetworkState {
_NetworkState() : members(), dirty(false)
{
}
std::unordered_map<uint64_t, _MemberState> members;
bool dirty;
};
std::unordered_map<uint64_t,_NetworkState> _state;
std::unordered_map<uint64_t, _NetworkState> _state;
std::mutex _state_l;
std::atomic_bool _running;
@ -85,6 +80,6 @@ protected:
bool _storeOnlineState;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -8,48 +8,48 @@ using namespace nlohmann;
using namespace ZeroTier;
MemberNotificationReceiver::MemberNotificationReceiver(DB *p, pqxx::connection &c, const std::string &channel)
: pqxx::notification_receiver(c, channel)
, _psql(p)
MemberNotificationReceiver::MemberNotificationReceiver(DB* p, pqxx::connection& c, const std::string& channel) : pqxx::notification_receiver(c, channel), _psql(p)
{
fprintf(stderr, "initialize MemberNotificationReceiver\n");
}
void MemberNotificationReceiver::operator() (const std::string &payload, int packend_pid) {
void MemberNotificationReceiver::operator()(const std::string& payload, int packend_pid)
{
fprintf(stderr, "Member Notification received: %s\n", payload.c_str());
Metrics::pgsql_mem_notification++;
json tmp(json::parse(payload));
json &ov = tmp["old_val"];
json &nv = tmp["new_val"];
json& ov = tmp["old_val"];
json& nv = tmp["new_val"];
json oldConfig, newConfig;
if (ov.is_object()) oldConfig = ov;
if (nv.is_object()) newConfig = nv;
if (ov.is_object())
oldConfig = ov;
if (nv.is_object())
newConfig = nv;
if (oldConfig.is_object() || newConfig.is_object()) {
_psql->_memberChanged(oldConfig,newConfig,_psql->isReady());
_psql->_memberChanged(oldConfig, newConfig, _psql->isReady());
fprintf(stderr, "payload sent\n");
}
}
NetworkNotificationReceiver::NetworkNotificationReceiver(DB *p, pqxx::connection &c, const std::string &channel)
: pqxx::notification_receiver(c, channel)
, _psql(p)
NetworkNotificationReceiver::NetworkNotificationReceiver(DB* p, pqxx::connection& c, const std::string& channel) : pqxx::notification_receiver(c, channel), _psql(p)
{
fprintf(stderr, "initialize NetworkNotificationReceiver\n");
}
void NetworkNotificationReceiver::operator() (const std::string &payload, int packend_pid) {
void NetworkNotificationReceiver::operator()(const std::string& payload, int packend_pid)
{
fprintf(stderr, "Network Notification received: %s\n", payload.c_str());
Metrics::pgsql_net_notification++;
json tmp(json::parse(payload));
json &ov = tmp["old_val"];
json &nv = tmp["new_val"];
json& ov = tmp["old_val"];
json& nv = tmp["new_val"];
json oldConfig, newConfig;
if (ov.is_object()) oldConfig = ov;
if (nv.is_object()) newConfig = nv;
if (ov.is_object())
oldConfig = ov;
if (nv.is_object())
newConfig = nv;
if (oldConfig.is_object() || newConfig.is_object()) {
_psql->_networkChanged(oldConfig,newConfig,_psql->isReady());
_psql->_networkChanged(oldConfig, newConfig, _psql->isReady());
fprintf(stderr, "payload sent\n");
}
}

View file

@ -16,10 +16,11 @@
#ifndef ZT_CONTROLLER_POSTGRESQL_HPP
#define ZT_CONTROLLER_POSTGRESQL_HPP
#include "DB.hpp"
#include "ConnectionPool.hpp"
#include <pqxx/pqxx>
#include "DB.hpp"
#include <memory>
#include <pqxx/pqxx>
namespace ZeroTier {
@ -27,56 +28,60 @@ extern "C" {
typedef struct pg_conn PGconn;
}
class PostgresConnection : public Connection {
public:
virtual ~PostgresConnection() {
public:
virtual ~PostgresConnection()
{
}
std::shared_ptr<pqxx::connection> c;
int a;
};
class PostgresConnFactory : public ConnectionFactory {
public:
PostgresConnFactory(std::string &connString)
: m_connString(connString)
public:
PostgresConnFactory(std::string& connString) : m_connString(connString)
{
}
virtual std::shared_ptr<Connection> create() {
virtual std::shared_ptr<Connection> create()
{
Metrics::conn_counter++;
auto c = std::shared_ptr<PostgresConnection>(new PostgresConnection());
c->c = std::make_shared<pqxx::connection>(m_connString);
return std::static_pointer_cast<Connection>(c);
}
private:
private:
std::string m_connString;
};
class MemberNotificationReceiver : public pqxx::notification_receiver {
public:
MemberNotificationReceiver(DB *p, pqxx::connection &c, const std::string &channel);
virtual ~MemberNotificationReceiver() {
public:
MemberNotificationReceiver(DB* p, pqxx::connection& c, const std::string& channel);
virtual ~MemberNotificationReceiver()
{
fprintf(stderr, "MemberNotificationReceiver destroyed\n");
}
virtual void operator() (const std::string &payload, int backendPid);
private:
DB *_psql;
virtual void operator()(const std::string& payload, int backendPid);
private:
DB* _psql;
};
class NetworkNotificationReceiver : public pqxx::notification_receiver {
public:
NetworkNotificationReceiver(DB *p, pqxx::connection &c, const std::string &channel);
virtual ~NetworkNotificationReceiver() {
public:
NetworkNotificationReceiver(DB* p, pqxx::connection& c, const std::string& channel);
virtual ~NetworkNotificationReceiver()
{
fprintf(stderr, "NetworkNotificationReceiver destroyed\n");
};
virtual void operator() (const std::string &payload, int packend_pid);
private:
DB *_psql;
virtual void operator()(const std::string& payload, int packend_pid);
private:
DB* _psql;
};
struct NodeOnlineRecord {
@ -85,8 +90,8 @@ struct NodeOnlineRecord {
std::string osArch;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif // ZT_CONTROLLER_POSTGRESQL_HPP
#endif // ZT_CONTROLLER_POSTGRESQL_HPP
#endif // ZT_CONTROLLER_USE_LIBPQ
#endif // ZT_CONTROLLER_USE_LIBPQ

View file

@ -5,11 +5,11 @@
namespace ZeroTier {
struct RedisConfig {
std::string hostname;
int port;
std::string password;
bool clusterMode;
std::string hostname;
int port;
std::string password;
bool clusterMode;
};
}
} // namespace ZeroTier
#endif

View file

@ -11,9 +11,10 @@
*/
/****/
#include "Constants.hpp"
#include "AES.hpp"
#include "Constants.hpp"
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
@ -31,40 +32,40 @@ namespace ZeroTier {
namespace {
#define s_bmul32(N, x, y, rh, rl) \
uint32_t x0t_##N = (x) & 0x11111111U; \
uint32_t x1t_##N = (x) & 0x22222222U; \
uint32_t x2t_##N = (x) & 0x44444444U; \
uint32_t x3t_##N = (x) & 0x88888888U; \
uint32_t y0t_##N = (y) & 0x11111111U; \
uint32_t y1t_##N = (y) & 0x22222222U; \
uint32_t y2t_##N = (y) & 0x44444444U; \
uint32_t y3t_##N = (y) & 0x88888888U; \
uint64_t z0t_##N = (((uint64_t)x0t_##N * y0t_##N) ^ ((uint64_t)x1t_##N * y3t_##N) ^ ((uint64_t)x2t_##N * y2t_##N) ^ ((uint64_t)x3t_##N * y1t_##N)) & 0x1111111111111111ULL; \
uint64_t z1t_##N = (((uint64_t)x0t_##N * y1t_##N) ^ ((uint64_t)x1t_##N * y0t_##N) ^ ((uint64_t)x2t_##N * y3t_##N) ^ ((uint64_t)x3t_##N * y2t_##N)) & 0x2222222222222222ULL; \
uint64_t z2t_##N = (((uint64_t)x0t_##N * y2t_##N) ^ ((uint64_t)x1t_##N * y1t_##N) ^ ((uint64_t)x2t_##N * y0t_##N) ^ ((uint64_t)x3t_##N * y3t_##N)) & 0x4444444444444444ULL; \
z0t_##N |= z1t_##N; \
z2t_##N |= z0t_##N; \
uint64_t zt_##N = z2t_##N | ((((uint64_t)x0t_##N * y3t_##N) ^ ((uint64_t)x1t_##N * y2t_##N) ^ ((uint64_t)x2t_##N * y1t_##N) ^ ((uint64_t)x3t_##N * y0t_##N)) & 0x8888888888888888ULL); \
(rh) = (uint32_t)(zt_##N >> 32U); \
#define s_bmul32(N, x, y, rh, rl) \
uint32_t x0t_##N = (x) & 0x11111111U; \
uint32_t x1t_##N = (x) & 0x22222222U; \
uint32_t x2t_##N = (x) & 0x44444444U; \
uint32_t x3t_##N = (x) & 0x88888888U; \
uint32_t y0t_##N = (y) & 0x11111111U; \
uint32_t y1t_##N = (y) & 0x22222222U; \
uint32_t y2t_##N = (y) & 0x44444444U; \
uint32_t y3t_##N = (y) & 0x88888888U; \
uint64_t z0t_##N = (((uint64_t)x0t_##N * y0t_##N) ^ ((uint64_t)x1t_##N * y3t_##N) ^ ((uint64_t)x2t_##N * y2t_##N) ^ ((uint64_t)x3t_##N * y1t_##N)) & 0x1111111111111111ULL; \
uint64_t z1t_##N = (((uint64_t)x0t_##N * y1t_##N) ^ ((uint64_t)x1t_##N * y0t_##N) ^ ((uint64_t)x2t_##N * y3t_##N) ^ ((uint64_t)x3t_##N * y2t_##N)) & 0x2222222222222222ULL; \
uint64_t z2t_##N = (((uint64_t)x0t_##N * y2t_##N) ^ ((uint64_t)x1t_##N * y1t_##N) ^ ((uint64_t)x2t_##N * y0t_##N) ^ ((uint64_t)x3t_##N * y3t_##N)) & 0x4444444444444444ULL; \
z0t_##N |= z1t_##N; \
z2t_##N |= z0t_##N; \
uint64_t zt_##N = z2t_##N | ((((uint64_t)x0t_##N * y3t_##N) ^ ((uint64_t)x1t_##N * y2t_##N) ^ ((uint64_t)x2t_##N * y1t_##N) ^ ((uint64_t)x3t_##N * y0t_##N)) & 0x8888888888888888ULL); \
(rh) = (uint32_t)(zt_##N >> 32U); \
(rl) = (uint32_t)zt_##N;
void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) noexcept
void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t& y0, uint64_t& y1) noexcept
{
uint32_t hhh = (uint32_t)(hh >> 32U);
uint32_t hhl = (uint32_t)hh;
uint32_t hlh = (uint32_t)(hl >> 32U);
uint32_t hll = (uint32_t)hl;
uint32_t hhXlh = hhh ^hlh;
uint32_t hhXll = hhl ^hll;
uint32_t hhXlh = hhh ^ hlh;
uint32_t hhXll = hhl ^ hll;
uint64_t yl = Utils::ntoh(y0);
uint64_t yh = Utils::ntoh(y1);
uint32_t cilh = (uint32_t)(yh >> 32U);
uint32_t cill = (uint32_t)yh;
uint32_t cihh = (uint32_t)(yl >> 32U);
uint32_t cihl = (uint32_t)yl;
uint32_t cihXlh = cihh ^cilh;
uint32_t cihXll = cihl ^cill;
uint32_t cihXlh = cihh ^ cilh;
uint32_t cihXll = cihl ^ cill;
uint32_t aah, aal, abh, abl, ach, acl;
s_bmul32(M0, cihh, hhh, aah, aal);
s_bmul32(M1, cihl, hhl, abh, abl);
@ -94,8 +95,8 @@ void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) n
cbh ^= bbh ^ abh;
cbl ^= bbl ^ abl;
uint64_t zhh = ((uint64_t)aah << 32U) | aal;
uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^(((uint64_t)cah << 32U) | cal);
uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^(((uint64_t)cbh << 32U) | cbl);
uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^ (((uint64_t)cah << 32U) | cal);
uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^ (((uint64_t)cbh << 32U) | cbl);
uint64_t zll = ((uint64_t)bbh << 32U) | bbl;
zhh = zhh << 1U | zhl >> 63U;
zhl = zhl << 1U | zlh >> 63U;
@ -108,11 +109,11 @@ void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) n
y1 = Utils::hton(zhl);
}
} // anonymous namespace
} // anonymous namespace
void AES::GMAC::update(const void *const data, unsigned int len) noexcept
void AES::GMAC::update(const void* const data, unsigned int len) noexcept
{
const uint8_t *in = reinterpret_cast<const uint8_t *>(data);
const uint8_t* in = reinterpret_cast<const uint8_t*>(data);
_len += len;
#ifdef ZT_AES_AESNI
@ -120,14 +121,14 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
p_aesNIUpdate(in, len);
return;
}
#endif // ZT_AES_AESNI
#endif // ZT_AES_AESNI
#ifdef ZT_AES_NEON
if (Utils::ARMCAP.pmull) {
p_armUpdate(in, len);
return;
}
#endif // ZT_AES_NEON
#endif // ZT_AES_NEON
const uint64_t h0 = _aes.p_k.sw.h[0];
const uint64_t h1 = _aes.p_k.sw.h[1];
@ -136,14 +137,14 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
if (_rp) {
for (;;) {
if (!len) {
if (! len) {
return;
}
--len;
_r[_rp++] = *(in++);
if (_rp == 16) {
y0 ^= Utils::loadMachineEndian< uint64_t >(_r);
y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8);
y0 ^= Utils::loadMachineEndian<uint64_t>(_r);
y1 ^= Utils::loadMachineEndian<uint64_t>(_r + 8);
s_gfmul(h0, h1, y0, y1);
break;
}
@ -151,8 +152,8 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
}
while (len >= 16) {
y0 ^= Utils::loadMachineEndian< uint64_t >(in);
y1 ^= Utils::loadMachineEndian< uint64_t >(in + 8);
y0 ^= Utils::loadMachineEndian<uint64_t>(in);
y1 ^= Utils::loadMachineEndian<uint64_t>(in + 8);
in += 16;
s_gfmul(h0, h1, y0, y1);
len -= 16;
@ -164,7 +165,7 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[i];
}
_rp = len; // len is always less than 16 here
_rp = len; // len is always less than 16 here
}
void AES::GMAC::finish(uint8_t tag[16]) noexcept
@ -174,14 +175,14 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
p_aesNIFinish(tag);
return;
}
#endif // ZT_AES_AESNI
#endif // ZT_AES_AESNI
#ifdef ZT_AES_NEON
if (Utils::ARMCAP.pmull) {
p_armFinish(tag);
return;
}
#endif // ZT_AES_NEON
#endif // ZT_AES_NEON
const uint64_t h0 = _aes.p_k.sw.h[0];
const uint64_t h1 = _aes.p_k.sw.h[1];
@ -192,8 +193,8 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
while (_rp < 16) {
_r[_rp++] = 0;
}
y0 ^= Utils::loadMachineEndian< uint64_t >(_r);
y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8);
y0 ^= Utils::loadMachineEndian<uint64_t>(_r);
y1 ^= Utils::loadMachineEndian<uint64_t>(_r + 8);
s_gfmul(h0, h1, y0, y1);
}
@ -201,57 +202,57 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
s_gfmul(h0, h1, y0, y1);
uint64_t iv2[2];
Utils::copy< 12 >(iv2, _iv);
Utils::copy<12>(iv2, _iv);
#if __BYTE_ORDER == __BIG_ENDIAN
reinterpret_cast<uint32_t *>(iv2)[3] = 0x00000001;
reinterpret_cast<uint32_t*>(iv2)[3] = 0x00000001;
#else
reinterpret_cast<uint32_t *>(iv2)[3] = 0x01000000;
reinterpret_cast<uint32_t*>(iv2)[3] = 0x01000000;
#endif
_aes.encrypt(iv2, iv2);
Utils::storeMachineEndian< uint64_t >(tag, iv2[0] ^ y0);
Utils::storeMachineEndian< uint64_t >(tag + 8, iv2[1] ^ y1);
Utils::storeMachineEndian<uint64_t>(tag, iv2[0] ^ y0);
Utils::storeMachineEndian<uint64_t>(tag + 8, iv2[1] ^ y1);
}
// AES-CTR ------------------------------------------------------------------------------------------------------------
void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
void AES::CTR::crypt(const void* const input, unsigned int len) noexcept
{
const uint8_t *in = reinterpret_cast<const uint8_t *>(input);
uint8_t *out = _out;
const uint8_t* in = reinterpret_cast<const uint8_t*>(input);
uint8_t* out = _out;
#ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) {
p_aesNICrypt(in, out, len);
return;
}
#endif // ZT_AES_AESNI
#endif // ZT_AES_AESNI
#ifdef ZT_AES_NEON
if (Utils::ARMCAP.aes) {
p_armCrypt(in, out, len);
return;
}
#endif // ZT_AES_NEON
#endif // ZT_AES_NEON
uint64_t keyStream[2];
uint32_t ctr = Utils::ntoh(reinterpret_cast<uint32_t *>(_ctr)[3]);
uint32_t ctr = Utils::ntoh(reinterpret_cast<uint32_t*>(_ctr)[3]);
unsigned int totalLen = _len;
if ((totalLen & 15U)) {
for (;;) {
if (!len) {
if (! len) {
_len = (totalLen + len);
return;
}
--len;
out[totalLen++] = *(in++);
if (!(totalLen & 15U)) {
_aes.p_encryptSW(reinterpret_cast<const uint8_t *>(_ctr), reinterpret_cast<uint8_t *>(keyStream));
reinterpret_cast<uint32_t *>(_ctr)[3] = Utils::hton(++ctr);
uint8_t *outblk = out + (totalLen - 16);
if (! (totalLen & 15U)) {
_aes.p_encryptSW(reinterpret_cast<const uint8_t*>(_ctr), reinterpret_cast<uint8_t*>(keyStream));
reinterpret_cast<uint32_t*>(_ctr)[3] = Utils::hton(++ctr);
uint8_t* outblk = out + (totalLen - 16);
for (int i = 0; i < 16; ++i) {
outblk[i] ^= reinterpret_cast<uint8_t *>(keyStream)[i];
outblk[i] ^= reinterpret_cast<uint8_t*>(keyStream)[i];
}
break;
}
@ -262,10 +263,10 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
_len = (totalLen + len);
if (likely(len >= 16)) {
const uint32_t *const restrict rk = _aes.p_k.sw.ek;
const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[0]) ^rk[0];
const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[1]) ^rk[1];
const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[2]) ^rk[2];
const uint32_t* const restrict rk = _aes.p_k.sw.ek;
const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[0]) ^ rk[0];
const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[1]) ^ rk[1];
const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[2]) ^ rk[2];
const uint32_t m8 = 0x000000ff;
const uint32_t m8_8 = 0x0000ff00;
const uint32_t m8_16 = 0x00ff0000;
@ -278,8 +279,8 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
s2 = ctr2rk2;
s3 = ctr++ ^ rk[3];
const uint64_t in0 = *reinterpret_cast<const uint64_t *>(in);
const uint64_t in1 = *reinterpret_cast<const uint64_t *>(in + 8);
const uint64_t in0 = *reinterpret_cast<const uint64_t*>(in);
const uint64_t in1 = *reinterpret_cast<const uint64_t*>(in + 8);
in += 16;
t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4];
@ -339,11 +340,12 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58];
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59];
*reinterpret_cast<uint64_t *>(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1);
*reinterpret_cast<uint64_t *>(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3);
*reinterpret_cast<uint64_t*>(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1);
*reinterpret_cast<uint64_t*>(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3);
out += 16;
} while ((len -= 16) >= 16);
} else {
}
else {
do {
uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
s0 = ctr0rk0;
@ -428,7 +430,7 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
in += 16;
} while ((len -= 16) >= 16);
}
reinterpret_cast<uint32_t *>(_ctr)[3] = Utils::hton(ctr);
reinterpret_cast<uint32_t*>(_ctr)[3] = Utils::hton(ctr);
}
// Any remaining input is placed in _out. This will be picked up and crypted
@ -454,48 +456,76 @@ void AES::CTR::finish() noexcept
// Software AES and AES key expansion ---------------------------------------------------------------------------------
const uint32_t AES::Te0[256] = {0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153,
0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba,
0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437,
0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878,
0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a};
const uint32_t AES::Te4[256] = {0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131,
0x15151515, 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575,
0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f,
0xa8a8a8a8, 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2,
0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373, 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4,
0x79797979, 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808,
0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a, 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, 0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828,
0xdfdfdfdf, 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616};
const uint32_t AES::Td0[256] = {0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c,
0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1,
0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e,
0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14,
0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742};
const uint8_t AES::Td4[256] = {0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d,
0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c,
0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d};
const uint32_t AES::rcon[15] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000};
const uint32_t AES::Te0[256] = { 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a };
const uint32_t AES::Te4[256] = { 0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676,
0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0,
0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131, 0x15151515,
0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575,
0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484,
0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf,
0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xa8a8a8a8,
0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2,
0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373,
0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb,
0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, 0x79797979,
0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808,
0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a,
0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e,
0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, 0xdfdfdfdf,
0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616 };
const uint32_t AES::Td0[256] = { 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 };
const uint8_t AES::Td4[256] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
const uint32_t AES::rcon[15] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000 };
void AES::p_initSW(const uint8_t *key) noexcept
void AES::p_initSW(const uint8_t* key) noexcept
{
uint32_t *rk = p_k.sw.ek;
uint32_t* rk = p_k.sw.ek;
rk[0] = Utils::loadBigEndian< uint32_t >(key);
rk[1] = Utils::loadBigEndian< uint32_t >(key + 4);
rk[2] = Utils::loadBigEndian< uint32_t >(key + 8);
rk[3] = Utils::loadBigEndian< uint32_t >(key + 12);
rk[4] = Utils::loadBigEndian< uint32_t >(key + 16);
rk[5] = Utils::loadBigEndian< uint32_t >(key + 20);
rk[6] = Utils::loadBigEndian< uint32_t >(key + 24);
rk[7] = Utils::loadBigEndian< uint32_t >(key + 28);
rk[0] = Utils::loadBigEndian<uint32_t>(key);
rk[1] = Utils::loadBigEndian<uint32_t>(key + 4);
rk[2] = Utils::loadBigEndian<uint32_t>(key + 8);
rk[3] = Utils::loadBigEndian<uint32_t>(key + 12);
rk[4] = Utils::loadBigEndian<uint32_t>(key + 16);
rk[5] = Utils::loadBigEndian<uint32_t>(key + 20);
rk[6] = Utils::loadBigEndian<uint32_t>(key + 24);
rk[7] = Utils::loadBigEndian<uint32_t>(key + 28);
for (int i = 0;;) {
uint32_t temp = rk[7];
rk[8] = rk[0] ^ (Te2_r((temp >> 16U) & 0xffU) & 0xff000000U) ^ (Te3_r((temp >> 8U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp) & 0xffU] & 0x0000ff00U) ^ (Te1_r(temp >> 24U) & 0x000000ffU) ^ rcon[i];
@ -513,7 +543,7 @@ void AES::p_initSW(const uint8_t *key) noexcept
rk += 8;
}
p_encryptSW((const uint8_t *)Utils::ZERO256, (uint8_t *)p_k.sw.h);
p_encryptSW((const uint8_t*)Utils::ZERO256, (uint8_t*)p_k.sw.h);
p_k.sw.h[0] = Utils::ntoh(p_k.sw.h[0]);
p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]);
@ -545,17 +575,17 @@ void AES::p_initSW(const uint8_t *key) noexcept
}
}
void AES::p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept
void AES::p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept
{
const uint32_t *const restrict rk = p_k.sw.ek;
const uint32_t* const restrict rk = p_k.sw.ek;
const uint32_t m8 = 0x000000ff;
const uint32_t m8_8 = 0x0000ff00;
const uint32_t m8_16 = 0x00ff0000;
const uint32_t m8_24 = 0xff000000;
uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0];
uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1];
uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2];
uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3];
uint32_t s0 = Utils::loadBigEndian<uint32_t>(in) ^ rk[0];
uint32_t s1 = Utils::loadBigEndian<uint32_t>(in + 4) ^ rk[1];
uint32_t s2 = Utils::loadBigEndian<uint32_t>(in + 8) ^ rk[2];
uint32_t s3 = Utils::loadBigEndian<uint32_t>(in + 12) ^ rk[3];
uint32_t t0, t1, t2, t3;
t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4];
@ -615,20 +645,20 @@ void AES::p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58];
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59];
Utils::storeBigEndian< uint32_t >(out, s0);
Utils::storeBigEndian< uint32_t >(out + 4, s1);
Utils::storeBigEndian< uint32_t >(out + 8, s2);
Utils::storeBigEndian< uint32_t >(out + 12, s3);
Utils::storeBigEndian<uint32_t>(out, s0);
Utils::storeBigEndian<uint32_t>(out + 4, s1);
Utils::storeBigEndian<uint32_t>(out + 8, s2);
Utils::storeBigEndian<uint32_t>(out + 12, s3);
}
void AES::p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept
void AES::p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept
{
const uint32_t *restrict rk = p_k.sw.dk;
const uint32_t* restrict rk = p_k.sw.dk;
const uint32_t m8 = 0x000000ff;
uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0];
uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1];
uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2];
uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3];
uint32_t s0 = Utils::loadBigEndian<uint32_t>(in) ^ rk[0];
uint32_t s1 = Utils::loadBigEndian<uint32_t>(in + 4) ^ rk[1];
uint32_t s2 = Utils::loadBigEndian<uint32_t>(in + 8) ^ rk[2];
uint32_t s3 = Utils::loadBigEndian<uint32_t>(in + 12) ^ rk[3];
uint32_t t0, t1, t2, t3;
t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[4];
@ -683,15 +713,15 @@ void AES::p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept
t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[53];
t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[54];
t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[55];
s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1) & m8]) ^ rk[56];
s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2) & m8]) ^ rk[57];
s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3) & m8]) ^ rk[58];
s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0) & m8]) ^ rk[59];
s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1)&m8]) ^ rk[56];
s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2)&m8]) ^ rk[57];
s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3)&m8]) ^ rk[58];
s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0)&m8]) ^ rk[59];
Utils::storeBigEndian< uint32_t >(out, s0);
Utils::storeBigEndian< uint32_t >(out + 4, s1);
Utils::storeBigEndian< uint32_t >(out + 8, s2);
Utils::storeBigEndian< uint32_t >(out + 12, s3);
Utils::storeBigEndian<uint32_t>(out, s0);
Utils::storeBigEndian<uint32_t>(out + 4, s1);
Utils::storeBigEndian<uint32_t>(out + 8, s2);
Utils::storeBigEndian<uint32_t>(out + 12, s3);
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -15,16 +15,16 @@
#define ZT_AES_HPP
#include "Constants.hpp"
#include "Utils.hpp"
#include "SHA512.hpp"
#include "Utils.hpp"
// Uncomment to disable all hardware acceleration (usually for testing)
//#define ZT_AES_NO_ACCEL
// #define ZT_AES_NO_ACCEL
#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64)
#if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64)
#define ZT_AES_AESNI 1
#endif
#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON) && defined(ZT_ARCH_ARM_HAS_CRYPTO)
#if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON) && defined(ZT_ARCH_ARM_HAS_CRYPTO)
#define ZT_AES_NEON 1
#endif
@ -40,9 +40,8 @@ namespace ZeroTier {
* This includes hardware acceleration for certain processors. The software
* mode is fallback and is significantly slower.
*/
class AES
{
public:
class AES {
public:
/**
* @return True if this system has hardware AES acceleration
*/
@ -63,39 +62,44 @@ public:
* Create an un-initialized AES instance (must call init() before use)
*/
ZT_INLINE AES() noexcept
{}
{
}
/**
* Create an AES instance with the given key
*
* @param key 256-bit key
*/
explicit ZT_INLINE AES(const void *const key) noexcept
{ this->init(key); }
explicit ZT_INLINE AES(const void* const key) noexcept
{
this->init(key);
}
ZT_INLINE ~AES()
{ Utils::burn(&p_k, sizeof(p_k)); }
{
Utils::burn(&p_k, sizeof(p_k));
}
/**
* Set (or re-set) this AES256 cipher's key
*
* @param key 256-bit / 32-byte key
*/
ZT_INLINE void init(const void *const key) noexcept
ZT_INLINE void init(const void* const key) noexcept
{
#ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) {
p_init_aesni(reinterpret_cast<const uint8_t *>(key));
p_init_aesni(reinterpret_cast<const uint8_t*>(key));
return;
}
#endif
#ifdef ZT_AES_NEON
if (Utils::ARMCAP.aes) {
p_init_armneon_crypto(reinterpret_cast<const uint8_t *>(key));
p_init_armneon_crypto(reinterpret_cast<const uint8_t*>(key));
return;
}
#endif
p_initSW(reinterpret_cast<const uint8_t *>(key));
p_initSW(reinterpret_cast<const uint8_t*>(key));
}
/**
@ -104,7 +108,7 @@ public:
* @param in Input block
* @param out Output block (can be same as input)
*/
ZT_INLINE void encrypt(const void *const in, void *const out) const noexcept
ZT_INLINE void encrypt(const void* const in, void* const out) const noexcept
{
#ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) {
@ -118,7 +122,7 @@ public:
return;
}
#endif
p_encryptSW(reinterpret_cast<const uint8_t *>(in), reinterpret_cast<uint8_t *>(out));
p_encryptSW(reinterpret_cast<const uint8_t*>(in), reinterpret_cast<uint8_t*>(out));
}
/**
@ -127,7 +131,7 @@ public:
* @param in Input block
* @param out Output block (can be same as input)
*/
ZT_INLINE void decrypt(const void *const in, void *const out) const noexcept
ZT_INLINE void decrypt(const void* const in, void* const out) const noexcept
{
#ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) {
@ -141,7 +145,7 @@ public:
return;
}
#endif
p_decryptSW(reinterpret_cast<const uint8_t *>(in), reinterpret_cast<uint8_t *>(out));
p_decryptSW(reinterpret_cast<const uint8_t*>(in), reinterpret_cast<uint8_t*>(out));
}
class GMACSIVEncryptor;
@ -150,12 +154,11 @@ public:
/**
* Streaming GMAC calculator
*/
class GMAC
{
class GMAC {
friend class GMACSIVEncryptor;
friend class GMACSIVDecryptor;
public:
public:
/**
* @return True if this system has hardware GMAC acceleration
*/
@ -177,8 +180,9 @@ public:
*
* @param aes Keyed AES instance to use
*/
ZT_INLINE GMAC(const AES &aes) : _aes(aes)
{}
ZT_INLINE GMAC(const AES& aes) : _aes(aes)
{
}
/**
* Reset and initialize for a new GMAC calculation
@ -192,12 +196,12 @@ public:
// We fill the least significant 32 bits in the _iv field with 1 since in GCM mode
// this would hold the counter, but we're not doing GCM. The counter is therefore
// always 1.
#ifdef ZT_AES_AESNI // also implies an x64 processor
*reinterpret_cast<uint64_t *>(_iv) = *reinterpret_cast<const uint64_t *>(iv);
*reinterpret_cast<uint32_t *>(_iv + 8) = *reinterpret_cast<const uint64_t *>(iv + 8);
*reinterpret_cast<uint32_t *>(_iv + 12) = 0x01000000; // 0x00000001 in big-endian byte order
#ifdef ZT_AES_AESNI // also implies an x64 processor
*reinterpret_cast<uint64_t*>(_iv) = *reinterpret_cast<const uint64_t*>(iv);
*reinterpret_cast<uint32_t*>(_iv + 8) = *reinterpret_cast<const uint64_t*>(iv + 8);
*reinterpret_cast<uint32_t*>(_iv + 12) = 0x01000000; // 0x00000001 in big-endian byte order
#else
for(int i=0;i<12;++i) {
for (int i = 0; i < 12; ++i) {
_iv[i] = iv[i];
}
_iv[12] = 0;
@ -215,7 +219,7 @@ public:
* @param data Bytes to process
* @param len Length of input
*/
void update(const void *data, unsigned int len) noexcept;
void update(const void* data, unsigned int len) noexcept;
/**
* Process any remaining cached bytes and generate tag
@ -226,19 +230,19 @@ public:
*/
void finish(uint8_t tag[16]) noexcept;
private:
private:
#ifdef ZT_AES_AESNI
void p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept;
void p_aesNIUpdate(const uint8_t* in, unsigned int len) noexcept;
void p_aesNIFinish(uint8_t tag[16]) noexcept;
#endif
#ifdef ZT_AES_NEON
void p_armUpdate(const uint8_t *in, unsigned int len) noexcept;
void p_armUpdate(const uint8_t* in, unsigned int len) noexcept;
void p_armFinish(uint8_t tag[16]) noexcept;
#endif
const AES &_aes;
const AES& _aes;
unsigned int _rp;
unsigned int _len;
uint8_t _r[16]; // remainder
uint8_t _r[16]; // remainder
uint8_t _iv[16];
uint64_t _y[2];
};
@ -249,14 +253,14 @@ public:
* NOTE: this doesn't support overflow of the counter in the least significant 32 bits.
* AES-GMAC-CTR doesn't need this, so we don't support it as an optimization.
*/
class CTR
{
class CTR {
friend class GMACSIVEncryptor;
friend class GMACSIVDecryptor;
public:
ZT_INLINE CTR(const AES &aes) noexcept: _aes(aes)
{}
public:
ZT_INLINE CTR(const AES& aes) noexcept : _aes(aes)
{
}
/**
* Initialize this CTR instance to encrypt a new stream
@ -264,10 +268,10 @@ public:
* @param iv Unique initialization vector and initial 32-bit counter (least significant 32 bits, big-endian)
* @param output Buffer to which to store output (MUST be large enough for total bytes processed!)
*/
ZT_INLINE void init(const uint8_t iv[16], void *const output) noexcept
ZT_INLINE void init(const uint8_t iv[16], void* const output) noexcept
{
Utils::copy< 16 >(_ctr, iv);
_out = reinterpret_cast<uint8_t *>(output);
Utils::copy<16>(_ctr, iv);
_out = reinterpret_cast<uint8_t*>(output);
_len = 0;
}
@ -278,11 +282,11 @@ public:
* @param ic Initial counter (must be in big-endian byte order!)
* @param output Buffer to which to store output (MUST be large enough for total bytes processed!)
*/
ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void *const output) noexcept
ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void* const output) noexcept
{
Utils::copy< 12 >(_ctr, iv);
reinterpret_cast<uint32_t *>(_ctr)[3] = ic;
_out = reinterpret_cast<uint8_t *>(output);
Utils::copy<12>(_ctr, iv);
reinterpret_cast<uint32_t*>(_ctr)[3] = ic;
_out = reinterpret_cast<uint8_t*>(output);
_len = 0;
}
@ -292,7 +296,7 @@ public:
* @param input Input data
* @param len Length of input
*/
void crypt(const void *input, unsigned int len) noexcept;
void crypt(const void* input, unsigned int len) noexcept;
/**
* Finish any remaining bytes if total bytes processed wasn't a multiple of 16
@ -301,16 +305,16 @@ public:
*/
void finish() noexcept;
private:
private:
#ifdef ZT_AES_AESNI
void p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept;
void p_aesNICrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept;
#endif
#ifdef ZT_AES_NEON
void p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept;
void p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept;
#endif
const AES &_aes;
const AES& _aes;
uint64_t _ctr[2];
uint8_t *_out;
uint8_t* _out;
unsigned int _len;
};
@ -325,19 +329,19 @@ public:
* This supports encryption of a maximum of 2^31 bytes of data per
* call to init().
*/
class GMACSIVEncryptor
{
public:
class GMACSIVEncryptor {
public:
/**
* Create a new AES-GMAC-SIV encryptor keyed with the provided AES instances
*
* @param k0 First of two AES instances keyed with K0
* @param k1 Second of two AES instances keyed with K1
*/
ZT_INLINE GMACSIVEncryptor(const AES &k0, const AES &k1) noexcept :
_gmac(k0),
_ctr(k1)
{}
ZT_INLINE GMACSIVEncryptor(const AES& k0, const AES& k1) noexcept
: _gmac(k0)
, _ctr(k1)
{
}
/**
* Initialize AES-GMAC-SIV
@ -345,7 +349,7 @@ public:
* @param iv IV in network byte order (byte order in which it will appear on the wire)
* @param output Pointer to buffer to receive ciphertext, must be large enough for all to-be-processed data!
*/
ZT_INLINE void init(const uint64_t iv, void *const output) noexcept
ZT_INLINE void init(const uint64_t iv, void* const output) noexcept
{
// Output buffer to receive the result of AES-CTR encryption.
_output = output;
@ -353,7 +357,7 @@ public:
// Initialize GMAC with 64-bit IV (and remaining 32 bits padded to zero).
_tag[0] = iv;
_tag[1] = 0;
_gmac.init(reinterpret_cast<const uint8_t *>(_tag));
_gmac.init(reinterpret_cast<const uint8_t*>(_tag));
}
/**
@ -367,7 +371,7 @@ public:
* @param aad Additional authenticated data
* @param len Length of AAD in bytes
*/
ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept
ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept
{
// Feed ADD into GMAC first
_gmac.update(aad, len);
@ -385,8 +389,10 @@ public:
* @param input Plaintext chunk
* @param len Length of plaintext chunk
*/
ZT_INLINE void update1(const void *const input, const unsigned int len) noexcept
{ _gmac.update(input, len); }
ZT_INLINE void update1(const void* const input, const unsigned int len) noexcept
{
_gmac.update(input, len);
}
/**
* Finish first pass, compute CTR IV, initialize second pass.
@ -395,7 +401,7 @@ public:
{
// Compute 128-bit GMAC tag.
uint64_t tmp[2];
_gmac.finish(reinterpret_cast<uint8_t *>(tmp));
_gmac.finish(reinterpret_cast<uint8_t*>(tmp));
// Shorten to 64 bits, concatenate with message IV, and encrypt with AES to
// yield the CTR IV and opaque IV/MAC blob. In ZeroTier's use of GMAC-SIV
@ -415,7 +421,7 @@ public:
// and so 2^31 should be considered the input limit.
tmp[0] = _tag[0];
tmp[1] = _tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL);
_ctr.init(reinterpret_cast<const uint8_t *>(tmp), _output);
_ctr.init(reinterpret_cast<const uint8_t*>(tmp), _output);
}
/**
@ -427,8 +433,10 @@ public:
* @param input Plaintext chunk
* @param len Length of plaintext chunk
*/
ZT_INLINE void update2(const void *const input, const unsigned int len) noexcept
{ _ctr.crypt(input, len); }
ZT_INLINE void update2(const void* const input, const unsigned int len) noexcept
{
_ctr.crypt(input, len);
}
/**
* Finish second pass and return a pointer to the opaque 128-bit IV+MAC block
@ -438,14 +446,14 @@ public:
*
* @return Pointer to 128-bit opaque IV+MAC (packed into two 64-bit integers)
*/
ZT_INLINE const uint64_t *finish2()
ZT_INLINE const uint64_t* finish2()
{
_ctr.finish();
return _tag;
}
private:
void *_output;
private:
void* _output;
uint64_t _tag[2];
AES::GMAC _gmac;
AES::CTR _ctr;
@ -456,13 +464,13 @@ public:
*
* GMAC-SIV decryption is single-pass. AAD (if any) must be processed first.
*/
class GMACSIVDecryptor
{
public:
ZT_INLINE GMACSIVDecryptor(const AES &k0, const AES &k1) noexcept:
_ctr(k1),
_gmac(k0)
{}
class GMACSIVDecryptor {
public:
ZT_INLINE GMACSIVDecryptor(const AES& k0, const AES& k1) noexcept
: _ctr(k1)
, _gmac(k0)
{
}
/**
* Initialize decryptor for a new message
@ -470,18 +478,18 @@ public:
* @param tag 128-bit combined IV/MAC originally created by GMAC-SIV encryption
* @param output Buffer in which to write output plaintext (must be large enough!)
*/
ZT_INLINE void init(const uint64_t tag[2], void *const output) noexcept
ZT_INLINE void init(const uint64_t tag[2], void* const output) noexcept
{
uint64_t tmp[2];
tmp[0] = tag[0];
tmp[1] = tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL);
_ctr.init(reinterpret_cast<const uint8_t *>(tmp), output);
_ctr.init(reinterpret_cast<const uint8_t*>(tmp), output);
_ctr._aes.decrypt(tag, _ivMac);
tmp[0] = _ivMac[0];
tmp[1] = 0;
_gmac.init(reinterpret_cast<const uint8_t *>(tmp));
_gmac.init(reinterpret_cast<const uint8_t*>(tmp));
_output = output;
_decryptedLen = 0;
@ -493,7 +501,7 @@ public:
* @param aad Additional authenticated data
* @param len Length of AAD in bytes
*/
ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept
ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept
{
_gmac.update(aad, len);
len &= 0xfU;
@ -510,7 +518,7 @@ public:
* @param input Input ciphertext
* @param len Length of ciphertext
*/
ZT_INLINE void update(const void *const input, const unsigned int len) noexcept
ZT_INLINE void update(const void* const input, const unsigned int len) noexcept
{
_ctr.crypt(input, len);
_decryptedLen += len;
@ -527,52 +535,48 @@ public:
uint64_t gmacTag[2];
_gmac.update(_output, _decryptedLen);
_gmac.finish(reinterpret_cast<uint8_t *>(gmacTag));
_gmac.finish(reinterpret_cast<uint8_t*>(gmacTag));
return (gmacTag[0] ^ gmacTag[1]) == _ivMac[1];
}
private:
private:
uint64_t _ivMac[2];
AES::CTR _ctr;
AES::GMAC _gmac;
void *_output;
void* _output;
unsigned int _decryptedLen;
};
private:
private:
static const uint32_t Te0[256];
static const uint32_t Te4[256];
static const uint32_t Td0[256];
static const uint8_t Td4[256];
static const uint32_t rcon[15];
void p_initSW(const uint8_t *key) noexcept;
void p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept;
void p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept;
void p_initSW(const uint8_t* key) noexcept;
void p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept;
void p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept;
union
{
union {
#ifdef ZT_AES_AESNI
struct
{
struct {
__m128i k[28];
__m128i h[4]; // h, hh, hhh, hhhh
__m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc.
__m128i h[4]; // h, hh, hhh, hhhh
__m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc.
} ni;
#endif
#ifdef ZT_AES_NEON
struct
{
uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens
struct {
uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens
uint8x16_t ek[15];
uint8x16_t dk[15];
uint8x16_t h;
} neon;
#endif
struct
{
struct {
uint64_t h[2];
uint32_t ek[60];
uint32_t dk[60];
@ -580,18 +584,18 @@ private:
} p_k;
#ifdef ZT_AES_AESNI
void p_init_aesni(const uint8_t *key) noexcept;
void p_encrypt_aesni(const void *in, void *out) const noexcept;
void p_decrypt_aesni(const void *in, void *out) const noexcept;
void p_init_aesni(const uint8_t* key) noexcept;
void p_encrypt_aesni(const void* in, void* out) const noexcept;
void p_decrypt_aesni(const void* in, void* out) const noexcept;
#endif
#ifdef ZT_AES_NEON
void p_init_armneon_crypto(const uint8_t *key) noexcept;
void p_encrypt_armneon_crypto(const void *in, void *out) const noexcept;
void p_decrypt_armneon_crypto(const void *in, void *out) const noexcept;
void p_init_armneon_crypto(const uint8_t* key) noexcept;
void p_encrypt_armneon_crypto(const void* in, void* out) const noexcept;
void p_decrypt_armneon_crypto(const void* in, void* out) const noexcept;
#endif
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,8 +11,8 @@
*/
/****/
#include "Constants.hpp"
#include "AES.hpp"
#include "Constants.hpp"
#ifdef ZT_AES_AESNI
@ -29,7 +29,8 @@ const __m128i s_sseSwapBytes = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
#ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul")))
#endif
__m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept
__m128i
p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept
{
y = _mm_shuffle_epi8(y, s_sseSwapBytes);
__m128i t1 = _mm_clmulepi64_si128(h, y, 0x00);
@ -55,7 +56,7 @@ __m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept
* The performance gain can be significant but regular SSE is already so
* fast it's highly unlikely to be a rate limiting factor except on massive
* servers and network infrastructure stuff. */
#if !defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7))
#if ! defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7))
#define ZT_AES_VAES512 1
@ -80,12 +81,8 @@ void p_aesCtrInnerVAES512(unsigned int &len, const uint64_t c0, uint64_t &c1, co
const __m512i kk13 = _mm512_broadcast_i32x4(k[13]);
const __m512i kk14 = _mm512_broadcast_i32x4(k[14]);
do {
__m512i p0 = _mm512_loadu_si512(reinterpret_cast<const __m512i *>(in));
__m512i d0 = _mm512_set_epi64(
(long long)Utils::hton(c1 + 3ULL), (long long)c0,
(long long)Utils::hton(c1 + 2ULL), (long long)c0,
(long long)Utils::hton(c1 + 1ULL), (long long)c0,
(long long)Utils::hton(c1), (long long)c0);
__m512i p0 = _mm512_loadu_si512(reinterpret_cast<const __m512i*>(in));
__m512i d0 = _mm512_set_epi64((long long)Utils::hton(c1 + 3ULL), (long long)c0, (long long)Utils::hton(c1 + 2ULL), (long long)c0, (long long)Utils::hton(c1 + 1ULL), (long long)c0, (long long)Utils::hton(c1), (long long)c0);
c1 += 4;
in += 64;
len -= 64;
@ -104,7 +101,7 @@ void p_aesCtrInnerVAES512(unsigned int &len, const uint64_t c0, uint64_t &c1, co
d0 = _mm512_aesenc_epi128(d0, kk12);
d0 = _mm512_aesenc_epi128(d0, kk13);
d0 = _mm512_aesenclast_epi128(d0, kk14);
_mm512_storeu_si512(reinterpret_cast<__m512i *>(out), _mm512_xor_si512(p0, d0));
_mm512_storeu_si512(reinterpret_cast<__m512i*>(out), _mm512_xor_si512(p0, d0));
out += 64;
} while (likely(len >= 64));
}
@ -132,14 +129,10 @@ void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, co
const __m256i kk13 = _mm256_broadcastsi128_si256(k[13]);
const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]);
do {
__m256i p0 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in));
__m256i p1 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in + 32));
__m256i d0 = _mm256_set_epi64x(
(long long)Utils::hton(c1 + 1ULL), (long long)c0,
(long long)Utils::hton(c1), (long long)c0);
__m256i d1 = _mm256_set_epi64x(
(long long)Utils::hton(c1 + 3ULL), (long long)c0,
(long long)Utils::hton(c1 + 2ULL), (long long)c0);
__m256i p0 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(in));
__m256i p1 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(in + 32));
__m256i d0 = _mm256_set_epi64x((long long)Utils::hton(c1 + 1ULL), (long long)c0, (long long)Utils::hton(c1), (long long)c0);
__m256i d1 = _mm256_set_epi64x((long long)Utils::hton(c1 + 3ULL), (long long)c0, (long long)Utils::hton(c1 + 2ULL), (long long)c0);
c1 += 4;
in += 64;
len -= 64;
@ -173,18 +166,19 @@ void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, co
d1 = _mm256_aesenc_epi128(d1, kk13);
d0 = _mm256_aesenclast_epi128(d0, kk14);
d1 = _mm256_aesenclast_epi128(d1, kk14);
_mm256_storeu_si256(reinterpret_cast<__m256i *>(out), _mm256_xor_si256(d0, p0));
_mm256_storeu_si256(reinterpret_cast<__m256i *>(out + 32), _mm256_xor_si256(d1, p1));
_mm256_storeu_si256(reinterpret_cast<__m256i*>(out), _mm256_xor_si256(d0, p0));
_mm256_storeu_si256(reinterpret_cast<__m256i*>(out + 32), _mm256_xor_si256(d1, p1));
out += 64;
} while (likely(len >= 64));
}
#endif // does compiler support AVX2 and AVX512 AES intrinsics?
#endif // does compiler support AVX2 and AVX512 AES intrinsics?
#ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif
__m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept
__m128i
p_init256_1_aesni(__m128i a, __m128i b) noexcept
{
__m128i x, y;
b = _mm_shuffle_epi32(b, 0xff);
@ -201,7 +195,8 @@ __m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept
#ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif
__m128i p_init256_2_aesni(__m128i a, __m128i b) noexcept
__m128i
p_init256_2_aesni(__m128i a, __m128i b) noexcept
{
__m128i x, y, z;
y = _mm_aeskeygenassist_si128(a, 0x00);
@ -216,25 +211,25 @@ __m128i p_init256_2_aesni(__m128i a, __m128i b) noexcept
return x;
}
} // anonymous namespace
} // anonymous namespace
#ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul")))
#endif
void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
{
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i *>(_y));
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i*>(_y));
// Handle anything left over from a previous run that wasn't a multiple of 16 bytes.
if (_rp) {
for (;;) {
if (!len) {
if (! len) {
return;
}
--len;
_r[_rp++] = *(in++);
if (_rp == 16) {
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r))));
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r))));
break;
}
}
@ -250,17 +245,21 @@ void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
const __m128i hh2 = _aes.p_k.ni.h2[1];
const __m128i hhh2 = _aes.p_k.ni.h2[2];
const __m128i hhhh2 = _aes.p_k.ni.h2[3];
const uint8_t *const end64 = in + (len & ~((unsigned int)63));
const uint8_t* const end64 = in + (len & ~((unsigned int)63));
len &= 63U;
do {
__m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))), sb);
__m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 16)), sb);
__m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 32)), sb);
__m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 48)), sb);
__m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))), sb);
__m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 16)), sb);
__m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 32)), sb);
__m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 48)), sb);
in += 64;
__m128i a = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x00), _mm_clmulepi64_si128(hhh, d2, 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x00), _mm_clmulepi64_si128(h, d4, 0x00)));
__m128i b = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x11), _mm_clmulepi64_si128(hhh, d2, 0x11)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x11), _mm_clmulepi64_si128(h, d4, 0x11)));
__m128i c = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00), _mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00), _mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))), _mm_xor_si128(a, b));
__m128i c = _mm_xor_si128(
_mm_xor_si128(
_mm_xor_si128(_mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00), _mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)),
_mm_xor_si128(_mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00), _mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))),
_mm_xor_si128(a, b));
a = _mm_xor_si128(_mm_slli_si128(c, 8), a);
b = _mm_xor_si128(_mm_srli_si128(c, 8), b);
c = _mm_srli_epi32(a, 31);
@ -274,18 +273,18 @@ void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
}
while (len >= 16) {
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))));
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))));
in += 16;
len -= 16;
}
_mm_storeu_si128(reinterpret_cast<__m128i *>(_y), y);
_mm_storeu_si128(reinterpret_cast<__m128i*>(_y), y);
// Any overflow is cached for a later run or finish().
for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[i];
}
_rp = len; // len is always less than 16 here
_rp = len; // len is always less than 16 here
}
#ifdef __GNUC__
@ -293,23 +292,23 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul,aes")))
#endif
void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept
{
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i *>(_y));
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i*>(_y));
// Handle any remaining bytes, padding the last block with zeroes.
if (_rp) {
while (_rp < 16) {
_r[_rp++] = 0;
}
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r))));
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r))));
}
// Interleave encryption of IV with the final GHASH of y XOR (length * 8).
// Then XOR these together to get the final tag.
const __m128i *const k = _aes.p_k.ni.k;
const __m128i* const k = _aes.p_k.ni.k;
const __m128i h = _aes.p_k.ni.h[0];
y = _mm_xor_si128(y, _mm_set_epi64x(0LL, (long long)Utils::hton((uint64_t)_len << 3U)));
y = _mm_shuffle_epi8(y, s_sseSwapBytes);
__m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i *>(_iv)), k[0]);
__m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i*>(_iv)), k[0]);
__m128i t1 = _mm_clmulepi64_si128(h, y, 0x00);
__m128i t2 = _mm_clmulepi64_si128(h, y, 0x01);
__m128i t3 = _mm_clmulepi64_si128(h, y, 0x10);
@ -359,7 +358,7 @@ void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept
t4 = _mm_xor_si128(t4, t3);
encIV = _mm_aesenclast_si128(encIV, k[14]);
t4 = _mm_xor_si128(t4, t5);
_mm_storeu_si128(reinterpret_cast<__m128i *>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV));
_mm_storeu_si128(reinterpret_cast<__m128i*>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV));
}
#ifdef __GNUC__
@ -370,7 +369,7 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
const __m128i dd = _mm_set_epi64x(0, (long long)_ctr[0]);
uint64_t c1 = Utils::ntoh(_ctr[1]);
const __m128i *const k = _aes.p_k.ni.k;
const __m128i* const k = _aes.p_k.ni.k;
const __m128i k0 = k[0];
const __m128i k1 = k[1];
const __m128i k2 = k[2];
@ -391,14 +390,14 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
unsigned int totalLen = _len;
if ((totalLen & 15U)) {
for (;;) {
if (unlikely(!len)) {
if (unlikely(! len)) {
_ctr[1] = Utils::hton(c1);
_len = totalLen;
return;
}
--len;
out[totalLen++] = *(in++);
if (!(totalLen & 15U)) {
if (! (totalLen & 15U)) {
__m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1);
d0 = _mm_xor_si128(d0, k0);
d0 = _mm_aesenc_si128(d0, k1);
@ -411,7 +410,7 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d0 = _mm_aesenc_si128(d0, k8);
d0 = _mm_aesenc_si128(d0, k9);
d0 = _mm_aesenc_si128(d0, k10);
__m128i *const outblk = reinterpret_cast<__m128i *>(out + (totalLen - 16));
__m128i* const outblk = reinterpret_cast<__m128i*>(out + (totalLen - 16));
d0 = _mm_aesenc_si128(d0, k11);
const __m128i p0 = _mm_loadu_si128(outblk);
d0 = _mm_aesenc_si128(d0, k12);
@ -427,26 +426,26 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
_len = totalLen + len;
if (likely(len >= 64)) {
#if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
if (Utils::CPUID.vaes && (len >= 256)) {
if (Utils::CPUID.avx512f) {
p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k);
} else {
}
else {
p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k);
}
goto skip_conventional_aesni_64;
}
#endif
#if !defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
#if ! defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
if (Utils::CPUID.vaes && (len >= 256)) {
p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k);
goto skip_conventional_aesni_64;
}
#endif
const uint8_t *const eof64 = in + (len & ~((unsigned int)63));
const uint8_t* const eof64 = in + (len & ~((unsigned int)63));
len &= 63;
__m128i d0, d1, d2, d3;
do {
@ -515,21 +514,20 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d1 = _mm_aesenc_si128(d1, k13);
d2 = _mm_aesenc_si128(d2, k13);
d3 = _mm_aesenc_si128(d3, k13);
d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)));
d1 = _mm_xor_si128(_mm_aesenclast_si128(d1, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 16)));
d2 = _mm_xor_si128(_mm_aesenclast_si128(d2, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 32)));
d3 = _mm_xor_si128(_mm_aesenclast_si128(d3, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 48)));
d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in)));
d1 = _mm_xor_si128(_mm_aesenclast_si128(d1, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 16)));
d2 = _mm_xor_si128(_mm_aesenclast_si128(d2, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 32)));
d3 = _mm_xor_si128(_mm_aesenclast_si128(d3, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 48)));
in += 64;
_mm_storeu_si128(reinterpret_cast<__m128i *>(out), d0);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 16), d1);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 32), d2);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 48), d3);
_mm_storeu_si128(reinterpret_cast<__m128i*>(out), d0);
_mm_storeu_si128(reinterpret_cast<__m128i*>(out + 16), d1);
_mm_storeu_si128(reinterpret_cast<__m128i*>(out + 32), d2);
_mm_storeu_si128(reinterpret_cast<__m128i*>(out + 48), d3);
out += 64;
} while (likely(in != eof64));
}
skip_conventional_aesni_64:
skip_conventional_aesni_64:
while (len >= 16) {
__m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1);
d0 = _mm_xor_si128(d0, k0);
@ -546,7 +544,7 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d0 = _mm_aesenc_si128(d0, k11);
d0 = _mm_aesenc_si128(d0, k12);
d0 = _mm_aesenc_si128(d0, k13);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out), _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))));
_mm_storeu_si128(reinterpret_cast<__m128i*>(out), _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))));
in += 16;
len -= 16;
out += 16;
@ -568,8 +566,8 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
void AES::p_init_aesni(const uint8_t *key) noexcept
{
__m128i t1, t2, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13;
p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i *)key);
p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i *)(key + 16));
p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i*)key);
p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i*)(key + 16));
p_k.ni.k[2] = k2 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x01));
p_k.ni.k[3] = k3 = t2 = p_init256_2_aesni(t1, t2);
p_k.ni.k[4] = k4 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x02));
@ -597,7 +595,7 @@ void AES::p_init_aesni(const uint8_t *key) noexcept
p_k.ni.k[26] = _mm_aesimc_si128(k2);
p_k.ni.k[27] = _mm_aesimc_si128(k1);
__m128i h = p_k.ni.k[0]; // _mm_xor_si128(_mm_setzero_si128(),_k.ni.k[0]);
__m128i h = p_k.ni.k[0]; // _mm_xor_si128(_mm_setzero_si128(),_k.ni.k[0]);
h = _mm_aesenc_si128(h, k1);
h = _mm_aesenc_si128(h, k2);
h = _mm_aesenc_si128(h, k3);
@ -631,7 +629,7 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif
void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept
{
__m128i tmp = _mm_loadu_si128((const __m128i *)in);
__m128i tmp = _mm_loadu_si128((const __m128i*)in);
tmp = _mm_xor_si128(tmp, p_k.ni.k[0]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[1]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[2]);
@ -646,7 +644,7 @@ void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[11]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[13]);
_mm_storeu_si128((__m128i *)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14]));
_mm_storeu_si128((__m128i*)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14]));
}
#ifdef __GNUC__
@ -654,7 +652,7 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif
void AES::p_decrypt_aesni(const void *in, void *out) const noexcept
{
__m128i tmp = _mm_loadu_si128((const __m128i *)in);
__m128i tmp = _mm_loadu_si128((const __m128i*)in);
tmp = _mm_xor_si128(tmp, p_k.ni.k[14]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[15]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[16]);
@ -669,9 +667,9 @@ void AES::p_decrypt_aesni(const void *in, void *out) const noexcept
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[25]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[27]);
_mm_storeu_si128((__m128i *)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0]));
_mm_storeu_si128((__m128i*)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0]));
}
} // namespace ZeroTier
} // namespace ZeroTier
#endif // ZT_AES_AESNI
#endif // ZT_AES_AESNI

View file

@ -11,8 +11,8 @@
*/
/****/
#include "Constants.hpp"
#include "AES.hpp"
#include "Constants.hpp"
#ifdef ZT_AES_NEON
@ -29,34 +29,34 @@ ZT_INLINE uint8x16_t s_clmul_armneon_crypto(uint8x16_t h, uint8x16_t y, const ui
y = vrbitq_u8(y);
const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087));
t0 = vextq_u8(y, y, 8);
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (r0) : "w" (h), "w" (y));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (r1) : "w" (h), "w" (y));
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t1) : "w" (h), "w" (t0));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (h), "w" (t0));
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(r0) : "w"(h), "w"(y));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(r1) : "w"(h), "w"(y));
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t1) : "w"(h), "w"(t0));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(h), "w"(t0));
t0 = veorq_u8(t0, t1);
t1 = vextq_u8(z, t0, 8);
r0 = veorq_u8(r0, t1);
t1 = vextq_u8(t0, z, 8);
r1 = veorq_u8(r1, t1);
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (r1), "w" (p));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(r1), "w"(p));
t1 = vextq_u8(t0, z, 8);
r1 = veorq_u8(r1, t1);
t1 = vextq_u8(z, t0, 8);
r0 = veorq_u8(r0, t1);
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t0) : "w" (r1), "w" (p));
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t0) : "w"(r1), "w"(p));
return vrbitq_u8(veorq_u8(r0, t0));
}
} // anonymous namespace
} // anonymous namespace
void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept
void AES::GMAC::p_armUpdate(const uint8_t* in, unsigned int len) noexcept
{
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t *>(_y));
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t*>(_y));
const uint8x16_t h = _aes.p_k.neon.h;
if (_rp) {
for(;;) {
if (!len) {
for (;;) {
if (! len) {
return;
}
--len;
@ -74,18 +74,18 @@ void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept
len -= 16;
}
vst1q_u8(reinterpret_cast<uint8_t *>(_y), y);
vst1q_u8(reinterpret_cast<uint8_t*>(_y), y);
for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[i];
}
_rp = len; // len is always less than 16 here
_rp = len; // len is always less than 16 here
}
void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept
{
uint64_t tmp[2];
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t *>(_y));
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t*>(_y));
const uint8x16_t h = _aes.p_k.neon.h;
if (_rp) {
@ -97,25 +97,25 @@ void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept
tmp[0] = Utils::hton((uint64_t)_len << 3U);
tmp[1] = 0;
y = s_clmul_armneon_crypto(h, y, reinterpret_cast<const uint8_t *>(tmp));
y = s_clmul_armneon_crypto(h, y, reinterpret_cast<const uint8_t*>(tmp));
Utils::copy< 12 >(tmp, _iv);
Utils::copy<12>(tmp, _iv);
#if __BYTE_ORDER == __BIG_ENDIAN
reinterpret_cast<uint32_t *>(tmp)[3] = 0x00000001;
reinterpret_cast<uint32_t*>(tmp)[3] = 0x00000001;
#else
reinterpret_cast<uint32_t *>(tmp)[3] = 0x01000000;
reinterpret_cast<uint32_t*>(tmp)[3] = 0x01000000;
#endif
_aes.encrypt(tmp, tmp);
uint8x16_t yy = y;
Utils::storeMachineEndian< uint64_t >(tag, tmp[0] ^ reinterpret_cast<const uint64_t *>(&yy)[0]);
Utils::storeMachineEndian< uint64_t >(tag + 8, tmp[1] ^ reinterpret_cast<const uint64_t *>(&yy)[1]);
Utils::storeMachineEndian<uint64_t>(tag, tmp[0] ^ reinterpret_cast<const uint64_t*>(&yy)[0]);
Utils::storeMachineEndian<uint64_t>(tag + 8, tmp[1] ^ reinterpret_cast<const uint64_t*>(&yy)[1]);
}
void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept
void AES::CTR::p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept
{
uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast<uint8_t *>(_ctr)));
const uint32x4_t one = {0,0,0,1};
uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast<uint8_t*>(_ctr)));
const uint32x4_t one = { 0, 0, 0, 1 };
uint8x16_t k0 = _aes.p_k.neon.ek[0];
uint8x16_t k1 = _aes.p_k.neon.ek[1];
@ -136,15 +136,15 @@ void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noe
unsigned int totalLen = _len;
if ((totalLen & 15U) != 0) {
for (;;) {
if (unlikely(!len)) {
vst1q_u8(reinterpret_cast<uint8_t *>(_ctr), vrev32q_u8(dd));
if (unlikely(! len)) {
vst1q_u8(reinterpret_cast<uint8_t*>(_ctr), vrev32q_u8(dd));
_len = totalLen;
return;
}
--len;
out[totalLen++] = *(in++);
if ((totalLen & 15U) == 0) {
uint8_t *const otmp = out + (totalLen - 16);
uint8_t* const otmp = out + (totalLen - 16);
uint8x16_t d0 = vrev32q_u8(dd);
uint8x16_t pt = vld1q_u8(otmp);
d0 = vaesmcq_u8(vaeseq_u8(d0, k0));
@ -298,46 +298,52 @@ void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noe
out[i] = in[i];
}
vst1q_u8(reinterpret_cast<uint8_t *>(_ctr), vrev32q_u8(dd));
vst1q_u8(reinterpret_cast<uint8_t*>(_ctr), vrev32q_u8(dd));
}
#define ZT_INIT_ARMNEON_CRYPTO_SUBWORD(w) ((uint32_t)s_sbox[w & 0xffU] + ((uint32_t)s_sbox[(w >> 8U) & 0xffU] << 8U) + ((uint32_t)s_sbox[(w >> 16U) & 0xffU] << 16U) + ((uint32_t)s_sbox[(w >> 24U) & 0xffU] << 24U))
#define ZT_INIT_ARMNEON_CRYPTO_ROTWORD(w) (((w) << 8U) | ((w) >> 24U))
#define ZT_INIT_ARMNEON_CRYPTO_NK 8
#define ZT_INIT_ARMNEON_CRYPTO_NB 4
#define ZT_INIT_ARMNEON_CRYPTO_NR 14
#define ZT_INIT_ARMNEON_CRYPTO_NK 8
#define ZT_INIT_ARMNEON_CRYPTO_NB 4
#define ZT_INIT_ARMNEON_CRYPTO_NR 14
void AES::p_init_armneon_crypto(const uint8_t *key) noexcept
void AES::p_init_armneon_crypto(const uint8_t* key) noexcept
{
static const uint8_t s_sbox[256] = {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c,
0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea,
0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
static const uint8_t s_sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
uint64_t h[2];
uint32_t *const w = reinterpret_cast<uint32_t *>(p_k.neon.ek);
uint32_t* const w = reinterpret_cast<uint32_t*>(p_k.neon.ek);
for (unsigned int i=0;i<ZT_INIT_ARMNEON_CRYPTO_NK;++i) {
for (unsigned int i = 0; i < ZT_INIT_ARMNEON_CRYPTO_NK; ++i) {
const unsigned int j = i * 4;
w[i] = ((uint32_t)key[j] << 24U) | ((uint32_t)key[j + 1] << 16U) | ((uint32_t)key[j + 2] << 8U) | (uint32_t)key[j + 3];
}
for (unsigned int i=ZT_INIT_ARMNEON_CRYPTO_NK;i<(ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1));++i) {
for (unsigned int i = ZT_INIT_ARMNEON_CRYPTO_NK; i < (ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1)); ++i) {
uint32_t t = w[i - 1];
const unsigned int imod = i & (ZT_INIT_ARMNEON_CRYPTO_NK - 1);
if (imod == 0) {
t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(ZT_INIT_ARMNEON_CRYPTO_ROTWORD(t)) ^ rcon[(i - 1) / ZT_INIT_ARMNEON_CRYPTO_NK];
} else if (imod == 4) {
}
else if (imod == 4) {
t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(t);
}
w[i] = w[i - ZT_INIT_ARMNEON_CRYPTO_NK] ^ t;
}
for (unsigned int i=0;i<(ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1));++i) {
for (unsigned int i = 0; i < (ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1)); ++i) {
w[i] = Utils::hton(w[i]);
}
p_k.neon.dk[0] = p_k.neon.ek[14];
for (int i=1;i<14;++i) {
for (int i = 1; i < 14; ++i) {
p_k.neon.dk[i] = vaesimcq_u8(p_k.neon.ek[14 - i]);
}
p_k.neon.dk[14] = p_k.neon.ek[0];
@ -349,9 +355,9 @@ void AES::p_init_armneon_crypto(const uint8_t *key) noexcept
p_k.sw.h[1] = Utils::ntoh(h[1]);
}
void AES::p_encrypt_armneon_crypto(const void *const in, void *const out) const noexcept
void AES::p_encrypt_armneon_crypto(const void* const in, void* const out) const noexcept
{
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t *>(in));
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t*>(in));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[0]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[2]));
@ -366,12 +372,12 @@ void AES::p_encrypt_armneon_crypto(const void *const in, void *const out) const
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[11]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[12]));
tmp = veorq_u8(vaeseq_u8(tmp, p_k.neon.ek[13]), p_k.neon.ek[14]);
vst1q_u8(reinterpret_cast<uint8_t *>(out), tmp);
vst1q_u8(reinterpret_cast<uint8_t*>(out), tmp);
}
void AES::p_decrypt_armneon_crypto(const void *const in, void *const out) const noexcept
void AES::p_decrypt_armneon_crypto(const void* const in, void* const out) const noexcept
{
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t *>(in));
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t*>(in));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[0]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[2]));
@ -386,9 +392,9 @@ void AES::p_decrypt_armneon_crypto(const void *const in, void *const out) const
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[11]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[12]));
tmp = veorq_u8(vaesdq_u8(tmp, p_k.neon.dk[13]), p_k.neon.dk[14]);
vst1q_u8(reinterpret_cast<uint8_t *>(out), tmp);
vst1q_u8(reinterpret_cast<uint8_t*>(out), tmp);
}
} // namespace ZeroTier
} // namespace ZeroTier
#endif // ZT_AES_NEON
#endif // ZT_AES_NEON

View file

@ -14,49 +14,64 @@
#ifndef ZT_ADDRESS_HPP
#define ZT_ADDRESS_HPP
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <string>
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
namespace ZeroTier {
/**
* A ZeroTier address
*/
class Address
{
public:
Address() : _a(0) {}
Address(const Address &a) : _a(a._a) {}
Address(uint64_t a) : _a(a & 0xffffffffffULL) {}
class Address {
public:
Address() : _a(0)
{
}
Address(const Address& a) : _a(a._a)
{
}
Address(uint64_t a) : _a(a & 0xffffffffffULL)
{
}
/**
* @param bits Raw address -- 5 bytes, big-endian byte order
* @param len Length of array
*/
Address(const void *bits,unsigned int len) { setTo(bits,len); }
Address(const void* bits, unsigned int len)
{
setTo(bits, len);
}
inline Address &operator=(const Address &a) { _a = a._a; return *this; }
inline Address &operator=(const uint64_t a) { _a = (a & 0xffffffffffULL); return *this; }
inline Address& operator=(const Address& a)
{
_a = a._a;
return *this;
}
inline Address& operator=(const uint64_t a)
{
_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,const unsigned int len)
inline void setTo(const void* bits, const unsigned int len)
{
if (len < ZT_ADDRESS_LENGTH) {
_a = 0;
return;
}
const unsigned char *b = (const unsigned char *)bits;
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;
@ -69,12 +84,12 @@ public:
* @param bits Buffer to hold 5-byte address in big-endian byte order
* @param len Length of array
*/
inline void copyTo(void *const bits,const unsigned int len) const
inline void copyTo(void* const bits, const unsigned int len) const
{
if (len < ZT_ADDRESS_LENGTH) {
return;
}
unsigned char *b = (unsigned char *)bits;
unsigned char* b = (unsigned char*)bits;
*(b++) = (unsigned char)((_a >> 32) & 0xff);
*(b++) = (unsigned char)((_a >> 24) & 0xff);
*(b++) = (unsigned char)((_a >> 16) & 0xff);
@ -87,10 +102,9 @@ public:
*
* @param b Buffer to append to
*/
template<unsigned int C>
inline void appendTo(Buffer<C> &b) const
template <unsigned int C> inline void appendTo(Buffer<C>& b) const
{
unsigned char *p = (unsigned char *)b.appendField(ZT_ADDRESS_LENGTH);
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);
@ -101,22 +115,34 @@ public:
/**
* @return Integer containing address (0 to 2^40)
*/
inline uint64_t toInt() const { return _a; }
inline uint64_t toInt() const
{
return _a;
}
/**
* @return Hash code for use with Hashtable
*/
inline unsigned long hashCode() const { return (unsigned long)_a; }
inline unsigned long hashCode() const
{
return (unsigned long)_a;
}
/**
* @return Hexadecimal string
*/
inline char *toString(char buf[11]) const { return Utils::hex10(_a,buf); }
inline char* toString(char buf[11]) const
{
return Utils::hex10(_a, buf);
}
/**
* @return True if this address is not zero
*/
inline operator bool() const { return (_a != 0); }
inline operator bool() const
{
return (_a != 0);
}
/**
* Check if this address is reserved
@ -127,34 +153,79 @@ public:
*
* @return True if address is reserved and may not be used
*/
inline bool isReserved() const { return ((!_a)||((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX)); }
inline bool isReserved() const
{
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 uint8_t operator[](unsigned int i) const { return (uint8_t)(_a >> (32 - (i * 8))); }
inline uint8_t operator[](unsigned int i) const
{
return (uint8_t)(_a >> (32 - (i * 8)));
}
inline void zero() { _a = 0; }
inline void zero()
{
_a = 0;
}
inline bool operator==(const uint64_t &a) const { return (_a == (a & 0xffffffffffULL)); }
inline bool operator!=(const uint64_t &a) const { return (_a != (a & 0xffffffffffULL)); }
inline bool operator>(const uint64_t &a) const { return (_a > (a & 0xffffffffffULL)); }
inline bool operator<(const uint64_t &a) const { return (_a < (a & 0xffffffffffULL)); }
inline bool operator>=(const uint64_t &a) const { return (_a >= (a & 0xffffffffffULL)); }
inline bool operator<=(const uint64_t &a) const { return (_a <= (a & 0xffffffffffULL)); }
inline bool operator==(const uint64_t& a) const
{
return (_a == (a & 0xffffffffffULL));
}
inline bool operator!=(const uint64_t& a) const
{
return (_a != (a & 0xffffffffffULL));
}
inline bool operator>(const uint64_t& a) const
{
return (_a > (a & 0xffffffffffULL));
}
inline bool operator<(const uint64_t& a) const
{
return (_a < (a & 0xffffffffffULL));
}
inline bool operator>=(const uint64_t& a) const
{
return (_a >= (a & 0xffffffffffULL));
}
inline bool operator<=(const uint64_t& a) const
{
return (_a <= (a & 0xffffffffffULL));
}
inline bool operator==(const Address &a) const { return (_a == a._a); }
inline bool operator!=(const Address &a) const { return (_a != a._a); }
inline bool operator>(const Address &a) const { return (_a > a._a); }
inline bool operator<(const Address &a) const { return (_a < a._a); }
inline bool operator>=(const Address &a) const { return (_a >= a._a); }
inline bool operator<=(const Address &a) const { return (_a <= a._a); }
inline bool operator==(const Address& a) const
{
return (_a == a._a);
}
inline bool operator!=(const Address& a) const
{
return (_a != a._a);
}
inline bool operator>(const Address& a) const
{
return (_a > a._a);
}
inline bool operator<(const Address& a) const
{
return (_a < a._a);
}
inline bool operator>=(const Address& a) const
{
return (_a >= a._a);
}
inline bool operator<=(const Address& a) const
{
return (_a <= a._a);
}
private:
private:
uint64_t _a;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -25,15 +25,17 @@ namespace ZeroTier {
/**
* Simple atomic counter supporting increment and decrement
*/
class AtomicCounter
{
public:
AtomicCounter() { _v = 0; }
class AtomicCounter {
public:
AtomicCounter()
{
_v = 0;
}
inline int load() const
{
#ifdef __GNUC__
return __sync_or_and_fetch(const_cast<int *>(&_v),0);
return __sync_or_and_fetch(const_cast<int*>(&_v), 0);
#else
return _v.load();
#endif
@ -42,7 +44,7 @@ public:
inline int operator++()
{
#ifdef __GNUC__
return __sync_add_and_fetch(&_v,1);
return __sync_add_and_fetch(&_v, 1);
#else
return ++_v;
#endif
@ -51,15 +53,20 @@ public:
inline int operator--()
{
#ifdef __GNUC__
return __sync_sub_and_fetch(&_v,1);
return __sync_sub_and_fetch(&_v, 1);
#else
return --_v;
#endif
}
private:
AtomicCounter(const AtomicCounter &) {}
const AtomicCounter &operator=(const AtomicCounter &) { return *this; }
private:
AtomicCounter(const AtomicCounter&)
{
}
const AtomicCounter& operator=(const AtomicCounter&)
{
return *this;
}
#ifdef __GNUC__
int _v;
@ -68,6 +75,6 @@ private:
#endif
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -373,7 +373,7 @@ SharedPtr<Path> Bond::getAppropriatePath(int64_t now, int32_t flowId)
*/
if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) {
if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS && _paths[_abPathIdx].p) {
//fprintf(stderr, "trying to send via (_abPathIdx=%d) %s\n", _abPathIdx, pathToStr(_paths[_abPathIdx].p).c_str());
// fprintf(stderr, "trying to send via (_abPathIdx=%d) %s\n", _abPathIdx, pathToStr(_paths[_abPathIdx].p).c_str());
return _paths[_abPathIdx].p;
}
}
@ -1584,7 +1584,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
}
}
}
if (!foundPreferredPath && foundPathOnPrimaryLink && (nonPreferredPathIdx != ZT_MAX_PEER_NETWORK_PATHS)) {
if (! foundPreferredPath && foundPathOnPrimaryLink && (nonPreferredPathIdx != ZT_MAX_PEER_NETWORK_PATHS)) {
log("found non-preferred primary link (_abPathIdx=%d)", _abPathIdx);
_abPathIdx = nonPreferredPathIdx;
}

View file

@ -1144,7 +1144,7 @@ class Bond {
__attribute__((format(printf, 2, 3)))
#endif
{
//if (_peerId != 0x0 && _peerId != 0x0) { return; }
// if (_peerId != 0x0 && _peerId != 0x0) { return; }
#ifdef ZT_TRACE
time_t rawtime;
struct tm* timeinfo;
@ -1176,7 +1176,7 @@ class Bond {
__attribute__((format(printf, 2, 3)))
#endif
{
//if (_peerId != 0x0 && _peerId != 0x0) { return; }
// if (_peerId != 0x0 && _peerId != 0x0) { return; }
#ifdef ZT_DEBUG
time_t rawtime;
struct tm* timeinfo;

View file

@ -14,18 +14,17 @@
#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))
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <string.h>
#include <string>
#include <utility>
#if defined(__GNUC__) && (! defined(ZT_NO_TYPE_PUNNING))
#define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__))
#else
#define ZT_VAR_MAY_ALIAS
@ -46,36 +45,57 @@ namespace ZeroTier {
*
* @tparam C Total capacity
*/
template<unsigned int C>
class Buffer
{
template <unsigned int C> class Buffer {
// I love me!
template <unsigned int C2> friend class Buffer;
public:
public:
// STL container idioms
typedef unsigned char value_type;
typedef unsigned char * pointer;
typedef const char * const_pointer;
typedef char & reference;
typedef const char & const_reference;
typedef char * iterator;
typedef const char * const_iterator;
typedef unsigned char* pointer;
typedef const char* const_pointer;
typedef char& reference;
typedef const char& const_reference;
typedef char* iterator;
typedef const 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()); }
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() :
_l(0)
Buffer() : _l(0)
{
}
@ -87,37 +107,36 @@ public:
_l = l;
}
template<unsigned int C2>
Buffer(const Buffer<C2> &b)
template <unsigned int C2> Buffer(const Buffer<C2>& b)
{
*this = b;
}
Buffer(const void *b,unsigned int l)
Buffer(const void* b, unsigned int l)
{
copyFrom(b,l);
copyFrom(b, l);
}
template<unsigned int C2>
inline Buffer &operator=(const Buffer<C2> &b)
template <unsigned int C2> inline Buffer& operator=(const Buffer<C2>& b)
{
if (unlikely(b._l > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
if (C2 == C) {
memcpy(this,&b,sizeof(Buffer<C>));
} else {
memcpy(_b,b._b,_l = b._l);
memcpy(this, &b, sizeof(Buffer<C>));
}
else {
memcpy(_b, b._b, _l = b._l);
}
return *this;
}
inline void copyFrom(const void *b,unsigned int l)
inline void copyFrom(const void* b, unsigned int l)
{
if (unlikely(l > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
memcpy(_b,b,l);
memcpy(_b, b, l);
_l = l;
}
@ -129,12 +148,12 @@ public:
return (unsigned char)_b[i];
}
unsigned char &operator[](const unsigned int i)
unsigned char& operator[](const unsigned int i)
{
if (unlikely(i >= _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
return ((unsigned char *)_b)[i];
return ((unsigned char*)_b)[i];
}
/**
@ -150,19 +169,19 @@ public:
* @return Pointer to field data
* @throws std::out_of_range Field extends beyond data size
*/
unsigned char *field(unsigned int i,unsigned int l)
unsigned char* field(unsigned int i, unsigned int l)
{
if (unlikely((i + l) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
return (unsigned char *)(_b + i);
return (unsigned char*)(_b + i);
}
const unsigned char *field(unsigned int i,unsigned int l) const
const unsigned char* field(unsigned int i, unsigned int l) const
{
if (unlikely((i + l) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
return (const unsigned char *)(_b + i);
return (const unsigned char*)(_b + i);
}
/**
@ -172,19 +191,18 @@ public:
* @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)
template <typename T> inline void setAt(unsigned int i, const T v)
{
if (unlikely((i + sizeof(T)) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
#ifdef ZT_NO_TYPE_PUNNING
uint8_t *p = reinterpret_cast<uint8_t *>(_b + i);
for(unsigned int x=1;x<=sizeof(T);++x) {
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);
T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T*>(_b + i);
*p = Utils::hton(v);
#endif
}
@ -196,22 +214,21 @@ public:
* @tparam T Integer type (e.g. uint16_t, int64_t)
* @return Integer value
*/
template<typename T>
inline T at(unsigned int i) const
template <typename T> inline T at(unsigned int i) const
{
if (unlikely((i + sizeof(T)) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
#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) {
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++);
v |= (T) * (p++);
}
return v;
#else
const T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T *>(_b + i);
const T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T*>(_b + i);
return Utils::ntoh(*p);
#endif
}
@ -223,19 +240,18 @@ public:
* @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)
template <typename T> inline void append(const T v)
{
if (unlikely((_l + sizeof(T)) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
#ifdef ZT_NO_TYPE_PUNNING
uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l);
for(unsigned int x=1;x<=sizeof(T);++x) {
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);
T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T*>(_b + _l);
*p = Utils::hton(v);
#endif
_l += sizeof(T);
@ -248,12 +264,12 @@ public:
* @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)
inline void append(unsigned char c, unsigned int n)
{
if (unlikely((_l + n) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
for(unsigned int i=0;i<n;++i) {
for (unsigned int i = 0; i < n; ++i) {
_b[_l++] = (char)c;
}
}
@ -268,7 +284,7 @@ public:
if (unlikely((_l + n) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
Utils::getSecureRandom(_b + _l,n);
Utils::getSecureRandom(_b + _l, n);
_l += n;
}
@ -279,12 +295,12 @@ public:
* @param l Length
* @throws std::out_of_range Attempt to append beyond capacity
*/
inline void append(const void *b,unsigned int l)
inline void append(const void* b, unsigned int l)
{
if (unlikely((_l + l) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
memcpy(_b + _l,b,l);
memcpy(_b + _l, b, l);
_l += l;
}
@ -294,13 +310,13 @@ public:
* @param s C string
* @throws std::out_of_range Attempt to append beyond capacity
*/
inline void appendCString(const char *s)
inline void appendCString(const char* s)
{
for(;;) {
for (;;) {
if (unlikely(_l >= C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
if (!(_b[_l++] = *(s++))) {
if (! (_b[_l++] = *(s++))) {
break;
}
}
@ -313,10 +329,9 @@ public:
* @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)
template <unsigned int C2> inline void append(const Buffer<C2>& b)
{
append(b._b,b._l);
append(b._b, b._l);
}
/**
@ -329,12 +344,12 @@ public:
* @param l Length of field to append
* @return Pointer to beginning of appended field of length 'l'
*/
inline char *appendField(unsigned int l)
inline char* appendField(unsigned int l)
{
if (unlikely((_l + l) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
char *r = _b + _l;
char* r = _b + _l;
_l += l;
return r;
}
@ -379,13 +394,13 @@ public:
*/
inline void behead(const unsigned int at)
{
if (!at) {
if (! at) {
return;
}
if (unlikely(at > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
::memmove(_b,_b + at,_l -= at);
::memmove(_b, _b + at, _l -= at);
}
/**
@ -395,92 +410,110 @@ public:
* @param length Length of block to erase
* @throws std::out_of_range Position plus length is beyond size of buffer
*/
inline void erase(const unsigned int at,const unsigned int length)
inline void erase(const unsigned int at, const unsigned int length)
{
const unsigned int endr = at + length;
if (unlikely(endr > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
::memmove(_b + at,_b + endr,_l - endr);
::memmove(_b + at, _b + endr, _l - endr);
_l -= length;
}
/**
* Set buffer data length to zero
*/
inline void clear() { _l = 0; }
inline void clear()
{
_l = 0;
}
/**
* Zero buffer up to size()
*/
inline void zero() { memset(_b,0,_l); }
inline void zero()
{
memset(_b, 0, _l);
}
/**
* Zero unused capacity area
*/
inline void zeroUnused() { memset(_b + _l,0,C - _l); }
inline void zeroUnused()
{
memset(_b + _l, 0, C - _l);
}
/**
* Unconditionally and securely zero buffer's underlying memory
*/
inline void burn() { Utils::burn(_b,sizeof(_b)); }
inline void burn()
{
Utils::burn(_b, sizeof(_b));
}
/**
* @return Constant pointer to data in buffer
*/
inline const void *data() const { return _b; }
inline const void* data() const
{
return _b;
}
/**
* @return Non-constant pointer to data in buffer
*/
inline void *unsafeData() { return _b; }
inline void* unsafeData()
{
return _b;
}
/**
* @return Size of data in buffer
*/
inline unsigned int size() const { return _l; }
inline unsigned int size() const
{
return _l;
}
/**
* @return Capacity of buffer
*/
inline unsigned int capacity() const { return C; }
inline unsigned int capacity() const
{
return C;
}
template<unsigned int C2>
inline bool operator==(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator==(const Buffer<C2>& b) const
{
return ((_l == b._l)&&(!memcmp(_b,b._b,_l)));
return ((_l == b._l) && (! memcmp(_b, b._b, _l)));
}
template<unsigned int C2>
inline bool operator!=(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator!=(const Buffer<C2>& b) const
{
return ((_l != b._l)||(memcmp(_b,b._b,_l)));
return ((_l != b._l) || (memcmp(_b, b._b, _l)));
}
template<unsigned int C2>
inline bool operator<(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator<(const Buffer<C2>& b) const
{
return (memcmp(_b,b._b,std::min(_l,b._l)) < 0);
return (memcmp(_b, b._b, std::min(_l, b._l)) < 0);
}
template<unsigned int C2>
inline bool operator>(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator>(const Buffer<C2>& b) const
{
return (b < *this);
}
template<unsigned int C2>
inline bool operator<=(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator<=(const Buffer<C2>& b) const
{
return !(b < *this);
return ! (b < *this);
}
template<unsigned int C2>
inline bool operator>=(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator>=(const Buffer<C2>& b) const
{
return !(*this < b);
return ! (*this < b);
}
private:
private:
char ZT_VAR_MAY_ALIAS _b[C];
unsigned int _l;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -18,20 +18,28 @@
namespace ZeroTier {
#define ZT_C25519_PUBLIC_KEY_LEN 64
#define ZT_C25519_PUBLIC_KEY_LEN 64
#define ZT_C25519_PRIVATE_KEY_LEN 64
#define ZT_C25519_SIGNATURE_LEN 96
#define ZT_C25519_SIGNATURE_LEN 96
/**
* A combined Curve25519 ECDH and Ed25519 signature engine
*/
class C25519
{
public:
struct Public { uint8_t data[ZT_C25519_PUBLIC_KEY_LEN]; };
struct Private { uint8_t data[ZT_C25519_PRIVATE_KEY_LEN]; };
struct Signature { uint8_t data[ZT_C25519_SIGNATURE_LEN]; };
struct Pair { Public pub; Private priv; };
class C25519 {
public:
struct Public {
uint8_t data[ZT_C25519_PUBLIC_KEY_LEN];
};
struct Private {
uint8_t data[ZT_C25519_PRIVATE_KEY_LEN];
};
struct Signature {
uint8_t data[ZT_C25519_SIGNATURE_LEN];
};
struct Pair {
Public pub;
Private priv;
};
/**
* Generate a C25519 elliptic curve key pair
@ -39,7 +47,7 @@ public:
static inline Pair generate()
{
Pair kp;
Utils::getSecureRandom(kp.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
Utils::getSecureRandom(kp.priv.data, ZT_C25519_PRIVATE_KEY_LEN);
_calcPubDH(kp);
_calcPubED(kp);
return kp;
@ -58,18 +66,17 @@ public:
* @return Key pair where cond(kp) returns true
* @tparam F Type of 'cond'
*/
template<typename F>
static inline Pair generateSatisfying(F cond)
template <typename F> static inline Pair generateSatisfying(F cond)
{
Pair kp;
void *const priv = (void *)kp.priv.data;
Utils::getSecureRandom(priv,ZT_C25519_PRIVATE_KEY_LEN);
_calcPubED(kp); // do Ed25519 key -- bytes 32-63 of pub and priv
void* const priv = (void*)kp.priv.data;
Utils::getSecureRandom(priv, ZT_C25519_PRIVATE_KEY_LEN);
_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));
++(((uint64_t*)priv)[1]);
--(((uint64_t*)priv)[2]);
_calcPubDH(kp); // keep regenerating bytes 0-31 until satisfied
} while (! cond(kp));
return kp;
}
@ -84,8 +91,11 @@ public:
* @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);
static inline void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen) { agree(mine.priv,their,keybuf,keylen); }
static void agree(const Private& mine, const Public& their, void* keybuf, unsigned int keylen);
static inline void agree(const Pair& mine, const Public& their, void* keybuf, unsigned int keylen)
{
agree(mine.priv, their, keybuf, keylen);
}
/**
* Sign a message with a sender's key pair
@ -106,8 +116,11 @@ public:
* @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);
static inline void sign(const Pair &mine,const void *msg,unsigned int len,void *signature) { sign(mine.priv,mine.pub,msg,len,signature); }
static void sign(const Private& myPrivate, const Public& myPublic, const void* msg, unsigned int len, void* signature);
static inline void sign(const Pair& mine, const void* msg, unsigned int len, void* signature)
{
sign(mine.priv, mine.pub, msg, len, signature);
}
/**
* Sign a message with a sender's key pair
@ -118,16 +131,16 @@ public:
* @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)
static inline Signature sign(const Private& myPrivate, const Public& myPublic, const void* msg, unsigned int len)
{
Signature sig;
sign(myPrivate,myPublic,msg,len,sig.data);
sign(myPrivate, myPublic, msg, len, sig.data);
return sig;
}
static inline Signature sign(const Pair &mine,const void *msg,unsigned int len)
static inline Signature sign(const Pair& mine, const void* msg, unsigned int len)
{
Signature sig;
sign(mine.priv,mine.pub,msg,len,sig.data);
sign(mine.priv, mine.pub, msg, len, sig.data);
return sig;
}
@ -140,7 +153,7 @@ public:
* @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);
static bool verify(const Public& their, const void* msg, unsigned int len, const void* signature);
/**
* Verify a message's signature
@ -151,21 +164,21 @@ public:
* @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)
static inline bool verify(const Public& their, const void* msg, unsigned int len, const Signature& signature)
{
return verify(their,msg,len,signature.data);
return verify(their, msg, len, signature.data);
}
private:
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);
static void _calcPubDH(Pair& kp);
// 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);
static void _calcPubED(Pair& kp);
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -12,54 +12,60 @@
/****/
#include "Capability.hpp"
#include "RuntimeEnvironment.hpp"
#include "Identity.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier {
int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const
int Capability::verify(const RuntimeEnvironment* RR, void* tPtr) const
{
try {
// There must be at least one entry, and sanity check for bad chain max length
if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
if ((_maxCustodyChainLength < 1) || (_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
return -1;
}
// Validate all entries in chain of custody
Buffer<(sizeof(Capability) * 2)> tmp;
this->serialize(tmp,true);
for(unsigned int c=0;c<_maxCustodyChainLength;++c) {
this->serialize(tmp, true);
for (unsigned int c = 0; c < _maxCustodyChainLength; ++c) {
if (c == 0) {
if ((!_custody[c].to)||(!_custody[c].from)||(_custody[c].from != Network::controllerFor(_nwid))) {
return -1; // the first entry must be present and from the network's controller
if ((! _custody[c].to) || (! _custody[c].from) || (_custody[c].from != Network::controllerFor(_nwid))) {
return -1; // the first entry must be present and from the network's controller
}
} else {
if (!_custody[c].to) {
return 0; // all previous entries were valid, so we are valid
} else if ((!_custody[c].from)||(_custody[c].from != _custody[c-1].to)) {
return -1; // otherwise if we have another entry it must be from the previous holder in the chain
}
else {
if (! _custody[c].to) {
return 0; // all previous entries were valid, so we are valid
}
else if ((! _custody[c].from) || (_custody[c].from != _custody[c - 1].to)) {
return -1; // otherwise if we have another entry it must be from the previous holder in the chain
}
}
const Identity id(RR->topology->getIdentity(tPtr,_custody[c].from));
const Identity id(RR->topology->getIdentity(tPtr, _custody[c].from));
if (id) {
if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature)) {
if (! id.verify(tmp.data(), tmp.size(), _custody[c].signature)) {
return -1;
}
} else {
RR->sw->requestWhois(tPtr,RR->node->now(),_custody[c].from);
}
else {
RR->sw->requestWhois(tPtr, RR->node->now(), _custody[c].from);
return 1;
}
}
// We reached max custody chain length and everything was valid
return 0;
} catch ( ... ) {}
}
catch (...) {
}
return -1;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,19 +14,19 @@
#ifndef ZT_CAPABILITY_HPP
#define ZT_CAPABILITY_HPP
#include "../include/ZeroTierOne.h"
#include "Address.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Constants.hpp"
#include "Credential.hpp"
#include "Address.hpp"
#include "C25519.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include "Identity.hpp"
#include "../include/ZeroTierOne.h"
namespace ZeroTier {
class RuntimeEnvironment;
@ -54,20 +54,17 @@ class RuntimeEnvironment;
* handed off between nodes. Limited transferability of capabilities is
* a feature of true capability based security.
*/
class Capability : public Credential
{
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_CAPABILITY; }
Capability() :
_nwid(0),
_ts(0),
_id(0),
_maxCustodyChainLength(0),
_ruleCount(0)
class Capability : public Credential {
public:
static inline Credential::Type credentialType()
{
memset(_rules,0,sizeof(_rules));
memset(_custody,0,sizeof(_custody));
return Credential::CREDENTIAL_TYPE_CAPABILITY;
}
Capability() : _nwid(0), _ts(0), _id(0), _maxCustodyChainLength(0), _ruleCount(0)
{
memset(_rules, 0, sizeof(_rules));
memset(_custody, 0, sizeof(_custody));
}
/**
@ -78,42 +75,57 @@ public:
* @param rules Network flow rules for this capability
* @param ruleCount Number of flow rules
*/
Capability(uint32_t id,uint64_t nwid,int64_t ts,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) :
_nwid(nwid),
_ts(ts),
_id(id),
_maxCustodyChainLength((mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1),
_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES)
Capability(uint32_t id, uint64_t nwid, int64_t ts, unsigned int mccl, const ZT_VirtualNetworkRule* rules, unsigned int ruleCount)
: _nwid(nwid)
, _ts(ts)
, _id(id)
, _maxCustodyChainLength((mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1)
, _ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES)
{
if (_ruleCount > 0) {
memcpy(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount);
memcpy(_rules, rules, sizeof(ZT_VirtualNetworkRule) * _ruleCount);
}
}
/**
* @return Rules -- see ruleCount() for size of array
*/
inline const ZT_VirtualNetworkRule *rules() const { return _rules; }
inline const ZT_VirtualNetworkRule* rules() const
{
return _rules;
}
/**
* @return Number of rules in rules()
*/
inline unsigned int ruleCount() const { return _ruleCount; }
inline unsigned int ruleCount() const
{
return _ruleCount;
}
/**
* @return ID and evaluation order of this capability in network
*/
inline uint32_t id() const { return _id; }
inline uint32_t id() const
{
return _id;
}
/**
* @return Network ID for which this capability was issued
*/
inline uint64_t networkId() const { return _nwid; }
inline uint64_t networkId() const
{
return _nwid;
}
/**
* @return Timestamp
*/
inline int64_t timestamp() const { return _ts; }
inline int64_t timestamp() const
{
return _ts;
}
/**
* @return Last 'to' address in chain of custody
@ -121,10 +133,11 @@ public:
inline Address issuedTo() const
{
Address i2;
for(unsigned int i=0;i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH;++i) {
if (!_custody[i].to) {
for (unsigned int i = 0; i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH; ++i) {
if (! _custody[i].to) {
return i2;
} else {
}
else {
i2 = _custody[i].to;
}
}
@ -144,20 +157,22 @@ public:
* @param to Recipient of this signature
* @return True if signature successful and chain of custody appended
*/
inline bool sign(const Identity &from,const Address &to)
inline bool sign(const Identity& from, const Address& to)
{
try {
for(unsigned int i=0;((i<_maxCustodyChainLength)&&(i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH));++i) {
if (!(_custody[i].to)) {
for (unsigned int i = 0; ((i < _maxCustodyChainLength) && (i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)); ++i) {
if (! (_custody[i].to)) {
Buffer<(sizeof(Capability) * 2)> tmp;
this->serialize(tmp,true);
this->serialize(tmp, true);
_custody[i].to = to;
_custody[i].from = from.address();
_custody[i].signature = from.sign(tmp.data(),tmp.size());
_custody[i].signature = from.sign(tmp.data(), tmp.size());
return true;
}
}
} catch ( ... ) {}
}
catch (...) {
}
return false;
}
@ -167,17 +182,16 @@ public:
* @param RR Runtime environment to provide for peer lookup, etc.
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain
*/
int verify(const RuntimeEnvironment *RR,void *tPtr) const;
int verify(const RuntimeEnvironment* RR, void* tPtr) const;
template<unsigned int C>
static inline void serializeRules(Buffer<C> &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
template <unsigned int C> static inline void serializeRules(Buffer<C>& b, const ZT_VirtualNetworkRule* rules, unsigned int ruleCount)
{
for(unsigned int i=0;i<ruleCount;++i) {
for (unsigned int i = 0; i < ruleCount; ++i) {
// Each rule consists of its 8-bit type followed by the size of that type's
// field followed by field data. The inclusion of the size will allow non-supported
// rules to be ignored but still parsed.
b.append((uint8_t)rules[i].t);
switch((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3f)) {
switch ((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3f)) {
default:
b.append((uint8_t)0);
break;
@ -187,7 +201,7 @@ public:
b.append((uint8_t)14);
b.append((uint64_t)rules[i].v.fwd.address);
b.append((uint32_t)rules[i].v.fwd.flags);
b.append((uint16_t)rules[i].v.fwd.length); // unused for redirect
b.append((uint16_t)rules[i].v.fwd.length); // unused for redirect
break;
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
@ -209,18 +223,18 @@ public:
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);
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(&(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(rules[i].v.ipv6.ip, 16);
b.append((uint8_t)rules[i].v.ipv6.mask);
break;
case ZT_NETWORK_RULE_MATCH_IP_TOS:
@ -276,7 +290,7 @@ public:
case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE:
b.append((uint8_t)19);
b.append((uint64_t)rules[i].v.intRange.start);
b.append((uint64_t)(rules[i].v.intRange.start + (uint64_t)rules[i].v.intRange.end)); // more future-proof
b.append((uint64_t)(rules[i].v.intRange.start + (uint64_t)rules[i].v.intRange.end)); // more future-proof
b.append((uint16_t)rules[i].v.intRange.idx);
b.append((uint8_t)rules[i].v.intRange.format);
break;
@ -284,13 +298,12 @@ public:
}
}
template<unsigned int C>
static inline void deserializeRules(const Buffer<C> &b,unsigned int &p,ZT_VirtualNetworkRule *rules,unsigned int &ruleCount,const unsigned int maxRuleCount)
template <unsigned int C> static inline void deserializeRules(const Buffer<C>& b, unsigned int& p, ZT_VirtualNetworkRule* rules, unsigned int& ruleCount, const unsigned int maxRuleCount)
{
while ((ruleCount < maxRuleCount)&&(p < b.size())) {
while ((ruleCount < maxRuleCount) && (p < b.size())) {
rules[ruleCount].t = (uint8_t)b[p++];
const unsigned int fieldLen = (unsigned int)b[p++];
switch((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) {
switch ((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) {
default:
break;
case ZT_NETWORK_RULE_ACTION_TEE:
@ -302,7 +315,7 @@ public:
break;
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
rules[ruleCount].v.zt = Address(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt();
rules[ruleCount].v.zt = Address(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH).toInt();
break;
case ZT_NETWORK_RULE_MATCH_VLAN_ID:
rules[ruleCount].v.vlanId = b.template at<uint16_t>(p);
@ -315,22 +328,22 @@ public:
break;
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
case ZT_NETWORK_RULE_MATCH_MAC_DEST:
memcpy(rules[ruleCount].v.mac,b.field(p,6),6);
memcpy(rules[ruleCount].v.mac, b.field(p, 6), 6);
break;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
memcpy(&(rules[ruleCount].v.ipv4.ip),b.field(p,4),4);
memcpy(&(rules[ruleCount].v.ipv4.ip), b.field(p, 4), 4);
rules[ruleCount].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[ruleCount].v.ipv6.ip,b.field(p,16),16);
memcpy(rules[ruleCount].v.ipv6.ip, b.field(p, 16), 16);
rules[ruleCount].v.ipv6.mask = (uint8_t)b[p + 16];
break;
case ZT_NETWORK_RULE_MATCH_IP_TOS:
rules[ruleCount].v.ipTos.mask = (uint8_t)b[p];
rules[ruleCount].v.ipTos.value[0] = (uint8_t)b[p+1];
rules[ruleCount].v.ipTos.value[1] = (uint8_t)b[p+2];
rules[ruleCount].v.ipTos.value[0] = (uint8_t)b[p + 1];
rules[ruleCount].v.ipTos.value[1] = (uint8_t)b[p + 2];
break;
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
rules[ruleCount].v.ipProtocol = (uint8_t)b[p];
@ -340,8 +353,8 @@ public:
break;
case ZT_NETWORK_RULE_MATCH_ICMP:
rules[ruleCount].v.icmp.type = (uint8_t)b[p];
rules[ruleCount].v.icmp.code = (uint8_t)b[p+1];
rules[ruleCount].v.icmp.flags = (uint8_t)b[p+2];
rules[ruleCount].v.icmp.code = (uint8_t)b[p + 1];
rules[ruleCount].v.icmp.flags = (uint8_t)b[p + 2];
break;
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
@ -380,8 +393,7 @@ public:
}
}
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
{
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -393,19 +405,20 @@ public:
b.append(_id);
b.append((uint16_t)_ruleCount);
serializeRules(b,_rules,_ruleCount);
serializeRules(b, _rules, _ruleCount);
b.append((uint8_t)_maxCustodyChainLength);
if (!forSign) {
for(unsigned int i=0;;++i) {
if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) {
if (! forSign) {
for (unsigned int i = 0;; ++i) {
if ((i < _maxCustodyChainLength) && (i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) && (_custody[i].to)) {
_custody[i].to.appendTo(b);
_custody[i].from.appendTo(b);
b.append((uint8_t)1); // 1 == Ed25519 signature
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_custody[i].signature.data,ZT_C25519_SIGNATURE_LEN);
} else {
b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain
b.append((uint8_t)1); // 1 == Ed25519 signature
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_custody[i].signature.data, ZT_C25519_SIGNATURE_LEN);
}
else {
b.append((unsigned char)0, ZT_ADDRESS_LENGTH); // zero 'to' terminates chain
break;
}
}
@ -419,8 +432,7 @@ public:
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
*this = Capability();
@ -438,33 +450,34 @@ public:
if (rc > ZT_MAX_CAPABILITY_RULES) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
deserializeRules(b,p,_rules,_ruleCount,rc);
deserializeRules(b, p, _rules, _ruleCount, rc);
_maxCustodyChainLength = (unsigned int)b[p++];
if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
if ((_maxCustodyChainLength < 1) || (_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
for(unsigned int i=0;;++i) {
const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
for (unsigned int i = 0;; ++i) {
const Address to(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (!to) {
if (! to) {
break;
}
if ((i >= _maxCustodyChainLength)||(i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
if ((i >= _maxCustodyChainLength) || (i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
_custody[i].to = to;
_custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
_custody[i].from.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
}
p += 2;
memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
memcpy(_custody[i].signature.data, b.field(p, ZT_C25519_SIGNATURE_LEN), ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else {
}
else {
p += 2 + b.template at<uint16_t>(p);
}
}
@ -478,12 +491,21 @@ public:
}
// Provides natural sort order by ID
inline bool operator<(const Capability &c) const { return (_id < c._id); }
inline bool operator<(const Capability& c) const
{
return (_id < c._id);
}
inline bool operator==(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) == 0); }
inline bool operator!=(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) != 0); }
inline bool operator==(const Capability& c) const
{
return (memcmp(this, &c, sizeof(Capability)) == 0);
}
inline bool operator!=(const Capability& c) const
{
return (memcmp(this, &c, sizeof(Capability)) != 0);
}
private:
private:
uint64_t _nwid;
int64_t _ts;
uint32_t _id;
@ -500,6 +522,6 @@ private:
} _custody[ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH];
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -12,15 +12,16 @@
/****/
#include "CertificateOfMembership.hpp"
#include "RuntimeEnvironment.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier {
CertificateOfMembership::CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Identity &issuedTo)
CertificateOfMembership::CertificateOfMembership(uint64_t timestamp, uint64_t timestampMaxDelta, uint64_t nwid, const Identity& issuedTo)
{
_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
_qualifiers[0].value = timestamp;
@ -36,34 +37,34 @@ CertificateOfMembership::CertificateOfMembership(uint64_t timestamp,uint64_t tim
// using the original COM format. Format may be revised in the future to make this cleaner.
uint64_t idHash[6];
issuedTo.publicKeyHash(idHash);
for(unsigned long i=0;i<4;++i) {
for (unsigned long i = 0; i < 4; ++i) {
_qualifiers[i + 3].id = (uint64_t)(i + 3);
_qualifiers[i + 3].value = Utils::ntoh(idHash[i]);
_qualifiers[i + 3].maxDelta = 0xffffffffffffffffULL;
}
_qualifierCount = 7;
memset(_signature.data,0,ZT_C25519_SIGNATURE_LEN);
memset(_signature.data, 0, ZT_C25519_SIGNATURE_LEN);
}
bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, const Identity &otherIdentity) const
bool CertificateOfMembership::agreesWith(const CertificateOfMembership& other, const Identity& otherIdentity) const
{
if ((_qualifierCount == 0)||(other._qualifierCount == 0)) {
if ((_qualifierCount == 0) || (other._qualifierCount == 0)) {
return false;
}
std::map< uint64_t, uint64_t > otherFields;
for(unsigned int i=0;i<other._qualifierCount;++i) {
std::map<uint64_t, uint64_t> otherFields;
for (unsigned int i = 0; i < other._qualifierCount; ++i) {
otherFields[other._qualifiers[i].id] = other._qualifiers[i].value;
}
bool fullIdentityVerification = false;
for(unsigned int i=0;i<_qualifierCount;++i) {
for (unsigned int i = 0; i < _qualifierCount; ++i) {
const uint64_t qid = _qualifiers[i].id;
if ((qid >= 3)&&(qid <= 6)) {
if ((qid >= 3) && (qid <= 6)) {
fullIdentityVerification = true;
}
std::map< uint64_t, uint64_t >::iterator otherQ(otherFields.find(qid));
std::map<uint64_t, uint64_t>::iterator otherQ(otherFields.find(qid));
if (otherQ == otherFields.end()) {
return false;
}
@ -79,8 +80,8 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, c
if (fullIdentityVerification) {
uint64_t idHash[6];
otherIdentity.publicKeyHash(idHash);
for(unsigned long i=0;i<4;++i) {
std::map< uint64_t, uint64_t >::iterator otherQ(otherFields.find((uint64_t)(i + 3)));
for (unsigned long i = 0; i < 4; ++i) {
std::map<uint64_t, uint64_t>::iterator otherQ(otherFields.find((uint64_t)(i + 3)));
if (otherQ == otherFields.end()) {
return false;
}
@ -93,46 +94,47 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, c
return true;
}
bool CertificateOfMembership::sign(const Identity &with)
bool CertificateOfMembership::sign(const Identity& with)
{
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
unsigned int ptr = 0;
for(unsigned int i=0;i<_qualifierCount;++i) {
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));
_signature = with.sign(buf, ptr * sizeof(uint64_t));
_signedBy = with.address();
return true;
} catch ( ... ) {
}
catch (...) {
_signedBy.zero();
return false;
}
}
int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) const
int CertificateOfMembership::verify(const RuntimeEnvironment* RR, void* tPtr) const
{
if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) {
if ((! _signedBy) || (_signedBy != Network::controllerFor(networkId())) || (_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) {
return -1;
}
const Identity id(RR->topology->getIdentity(tPtr,_signedBy));
if (!id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy);
const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (! id) {
RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1;
}
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
unsigned int ptr = 0;
for(unsigned int i=0;i<_qualifierCount;++i) {
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);
}
return (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1);
return (id.verify(buf, ptr * sizeof(uint64_t), _signature) ? 0 : -1);
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,21 +14,20 @@
#ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP
#define ZT_CERTIFICATEOFMEMBERSHIP_HPP
#include <stdint.h>
#include <string.h>
#include <string>
#include <stdexcept>
#include <algorithm>
#include "Address.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "Buffer.hpp"
#include "Address.hpp"
#include "C25519.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <string.h>
#include <string>
/**
* Maximum number of qualifiers allowed in a COM (absolute max: 65535)
*/
@ -64,10 +63,12 @@ class RuntimeEnvironment;
* This is a memcpy()'able structure and is safe (in a crash sense) to modify
* without locks.
*/
class CertificateOfMembership : public Credential
{
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COM; }
class CertificateOfMembership : public Credential {
public:
static inline Credential::Type credentialType()
{
return Credential::CREDENTIAL_TYPE_COM;
}
/**
* Reserved qualifier IDs
@ -78,8 +79,7 @@ public:
* Addition of new required fields requires that code in hasRequiredFields
* be updated as well.
*/
enum ReservedId
{
enum ReservedId {
/**
* Timestamp of certificate
*/
@ -101,8 +101,9 @@ public:
/**
* Create an empty certificate of membership
*/
CertificateOfMembership() :
_qualifierCount(0) {}
CertificateOfMembership() : _qualifierCount(0)
{
}
/**
* Create from required fields common to all networks
@ -112,7 +113,7 @@ public:
* @param nwid Network ID
* @param issuedTo Certificate recipient
*/
CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Identity &issuedTo);
CertificateOfMembership(uint64_t timestamp, uint64_t timestampMaxDelta, uint64_t nwid, const Identity& issuedTo);
/**
* Create from binary-serialized COM in buffer
@ -120,28 +121,33 @@ public:
* @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)
template <unsigned int C> CertificateOfMembership(const Buffer<C>& b, unsigned int startAt = 0)
{
deserialize(b,startAt);
deserialize(b, startAt);
}
/**
* @return True if there's something here
*/
inline operator bool() const { return (_qualifierCount != 0); }
inline operator bool() const
{
return (_qualifierCount != 0);
}
/**
* @return Credential ID, always 0 for COMs
*/
inline uint32_t id() const { return 0; }
inline uint32_t id() const
{
return 0;
}
/**
* @return Timestamp for this cert and maximum delta for timestamp
*/
inline int64_t timestamp() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
for (unsigned int i = 0; i < _qualifierCount; ++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) {
return _qualifiers[i].value;
}
@ -154,7 +160,7 @@ public:
*/
inline Address issuedTo() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
for (unsigned int i = 0; i < _qualifierCount; ++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) {
return Address(_qualifiers[i].value);
}
@ -167,7 +173,7 @@ public:
*/
inline uint64_t networkId() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
for (unsigned int i = 0; i < _qualifierCount; ++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) {
return _qualifiers[i].value;
}
@ -189,7 +195,7 @@ public:
* @param otherIdentity Identity of other node
* @return True if certs agree and 'other' may be communicated with
*/
bool agreesWith(const CertificateOfMembership &other, const Identity &otherIdentity) const;
bool agreesWith(const CertificateOfMembership& other, const Identity& otherIdentity) const;
/**
* Sign this certificate
@ -197,7 +203,7 @@ public:
* @param with Identity to sign with, must include private key
* @return True if signature was successful
*/
bool sign(const Identity &with);
bool sign(const Identity& with);
/**
* Verify this COM and its signature
@ -206,36 +212,40 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
*/
int verify(const RuntimeEnvironment *RR,void *tPtr) const;
int verify(const RuntimeEnvironment* RR, void* tPtr) const;
/**
* @return True if signed
*/
inline bool isSigned() const { return (_signedBy); }
inline bool isSigned() const
{
return (_signedBy);
}
/**
* @return Address that signed this certificate or null address if none
*/
inline const Address &signedBy() const { return _signedBy; }
inline const Address& signedBy() const
{
return _signedBy;
}
template<unsigned int C>
inline void serialize(Buffer<C> &b) const
template <unsigned int C> inline void serialize(Buffer<C>& b) const
{
b.append((uint8_t)1);
b.append((uint16_t)_qualifierCount);
for(unsigned int i=0;i<_qualifierCount;++i) {
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,ZT_C25519_SIGNATURE_LEN);
b.append(_signature.data, ZT_C25519_SIGNATURE_LEN);
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
unsigned int p = startAt;
@ -249,11 +259,12 @@ public:
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) {
for (unsigned int i = 0; i < numq; ++i) {
const uint64_t qid = b.template at<uint64_t>(p);
if (qid < lastId) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING;
} else {
}
else {
lastId = qid;
}
if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
@ -262,23 +273,24 @@ public:
_qualifiers[_qualifierCount].maxDelta = b.template at<uint64_t>(p + 16);
p += 24;
++_qualifierCount;
} else {
}
else {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
}
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
_signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (_signedBy) {
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
memcpy(_signature.data, b.field(p, ZT_C25519_SIGNATURE_LEN), ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
}
return (p - startAt);
}
inline bool operator==(const CertificateOfMembership &c) const
inline bool operator==(const CertificateOfMembership& c) const
{
if (_signedBy != c._signedBy) {
return false;
@ -286,25 +298,32 @@ public:
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)) {
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 (memcmp(_signature.data,c._signature.data,ZT_C25519_SIGNATURE_LEN) == 0);
return (memcmp(_signature.data, c._signature.data, ZT_C25519_SIGNATURE_LEN) == 0);
}
inline bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
private:
struct _Qualifier
inline bool operator!=(const CertificateOfMembership& c) const
{
_Qualifier() : id(0),value(0),maxDelta(0) {}
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 { return (id < q.id); } // sort order
inline bool operator<(const _Qualifier& q) const
{
return (id < q.id);
} // sort order
};
Address _signedBy;
@ -313,6 +332,6 @@ private:
C25519::Signature _signature;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -12,41 +12,43 @@
/****/
#include "CertificateOfOwnership.hpp"
#include "RuntimeEnvironment.hpp"
#include "Identity.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier {
int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) const
int CertificateOfOwnership::verify(const RuntimeEnvironment* RR, void* tPtr) const
{
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) {
if ((! _signedBy) || (_signedBy != Network::controllerFor(_networkId))) {
return -1;
}
const Identity id(RR->topology->getIdentity(tPtr,_signedBy));
if (!id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy);
const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (! id) {
RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1;
}
try {
Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp;
this->serialize(tmp,true);
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
} catch ( ... ) {
this->serialize(tmp, true);
return (id.verify(tmp.data(), tmp.size(), _signature) ? 0 : -1);
}
catch (...) {
return -1;
}
}
bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing &t,const void *v,unsigned int l) const
bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing& t, const void* v, unsigned int l) const
{
for(unsigned int i=0,j=_thingCount;i<j;++i) {
for (unsigned int i = 0, j = _thingCount; i < j; ++i) {
if (_thingTypes[i] == (uint8_t)t) {
unsigned int k = 0;
while (k < l) {
if (reinterpret_cast<const uint8_t *>(v)[k] != _thingValues[i][k]) {
if (reinterpret_cast<const uint8_t*>(v)[k] != _thingValues[i][k]) {
break;
}
++k;
@ -59,4 +61,4 @@ bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing &t,const
return false;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,20 +14,20 @@
#ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP
#define ZT_CERTIFICATEOFOWNERSHIP_HPP
#include "Address.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Constants.hpp"
#include "Credential.hpp"
#include "C25519.hpp"
#include "Address.hpp"
#include "Identity.hpp"
#include "Buffer.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
// Max things per CertificateOfOwnership
#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS 16
@ -41,84 +41,102 @@ class RuntimeEnvironment;
/**
* Certificate indicating ownership of a network identifier
*/
class CertificateOfOwnership : public Credential
{
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COO; }
enum Thing
class CertificateOfOwnership : public Credential {
public:
static inline Credential::Type credentialType()
{
THING_NULL = 0,
THING_MAC_ADDRESS = 1,
THING_IPV4_ADDRESS = 2,
THING_IPV6_ADDRESS = 3
};
return Credential::CREDENTIAL_TYPE_COO;
}
enum Thing { THING_NULL = 0, THING_MAC_ADDRESS = 1, THING_IPV4_ADDRESS = 2, THING_IPV6_ADDRESS = 3 };
CertificateOfOwnership()
{
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
memset(reinterpret_cast<void*>(this), 0, sizeof(CertificateOfOwnership));
}
CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id)
CertificateOfOwnership(const uint64_t nwid, const int64_t ts, const Address& issuedTo, const uint32_t id)
{
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
memset(reinterpret_cast<void*>(this), 0, sizeof(CertificateOfOwnership));
_networkId = nwid;
_ts = ts;
_id = id;
_issuedTo = issuedTo;
}
inline uint64_t networkId() const { return _networkId; }
inline int64_t timestamp() const { return _ts; }
inline uint32_t id() const { return _id; }
inline unsigned int thingCount() const { return (unsigned int)_thingCount; }
inline uint64_t networkId() const
{
return _networkId;
}
inline int64_t timestamp() const
{
return _ts;
}
inline uint32_t id() const
{
return _id;
}
inline unsigned int thingCount() const
{
return (unsigned int)_thingCount;
}
inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; }
inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; }
inline Thing thingType(const unsigned int i) const
{
return (Thing)_thingTypes[i];
}
inline const uint8_t* thingValue(const unsigned int i) const
{
return _thingValues[i];
}
inline const Address &issuedTo() const { return _issuedTo; }
inline const Address& issuedTo() const
{
return _issuedTo;
}
inline bool owns(const InetAddress &ip) const
inline bool owns(const InetAddress& ip) const
{
if (ip.ss_family == AF_INET) {
return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
return this->_owns(THING_IPV4_ADDRESS, &(reinterpret_cast<const struct sockaddr_in*>(&ip)->sin_addr.s_addr), 4);
}
if (ip.ss_family == AF_INET6) {
return this->_owns(THING_IPV6_ADDRESS,reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
return this->_owns(THING_IPV6_ADDRESS, reinterpret_cast<const struct sockaddr_in6*>(&ip)->sin6_addr.s6_addr, 16);
}
return false;
}
inline bool owns(const MAC &mac) const
inline bool owns(const MAC& mac) const
{
uint8_t tmp[6];
mac.copyTo(tmp,6);
return this->_owns(THING_MAC_ADDRESS,tmp,6);
mac.copyTo(tmp, 6);
return this->_owns(THING_MAC_ADDRESS, tmp, 6);
}
inline void addThing(const InetAddress &ip)
inline void addThing(const InetAddress& ip)
{
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
return;
}
if (ip.ss_family == AF_INET) {
_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
memcpy(_thingValues[_thingCount], &(reinterpret_cast<const struct sockaddr_in*>(&ip)->sin_addr.s_addr), 4);
++_thingCount;
} else if (ip.ss_family == AF_INET6) {
}
else if (ip.ss_family == AF_INET6) {
_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
memcpy(_thingValues[_thingCount], reinterpret_cast<const struct sockaddr_in6*>(&ip)->sin6_addr.s6_addr, 16);
++_thingCount;
}
}
inline void addThing(const MAC &mac)
inline void addThing(const MAC& mac)
{
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
return;
}
_thingTypes[_thingCount] = THING_MAC_ADDRESS;
mac.copyTo(_thingValues[_thingCount],6);
mac.copyTo(_thingValues[_thingCount], 6);
++_thingCount;
}
@ -126,13 +144,13 @@ public:
* @param signer Signing identity, must have private key
* @return True if signature was successful
*/
inline bool sign(const Identity &signer)
inline bool sign(const Identity& signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signature = signer.sign(tmp.data(),tmp.size());
this->serialize(tmp, true);
_signature = signer.sign(tmp.data(), tmp.size());
return true;
}
return false;
@ -143,10 +161,9 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature
*/
int verify(const RuntimeEnvironment *RR,void *tPtr) const;
int verify(const RuntimeEnvironment* RR, void* tPtr) const;
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
{
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -157,28 +174,27 @@ public:
b.append(_flags);
b.append(_id);
b.append((uint16_t)_thingCount);
for(unsigned int i=0,j=_thingCount;i<j;++i) {
for (unsigned int i = 0, j = _thingCount; i < j; ++i) {
b.append((uint8_t)_thingTypes[i]);
b.append(_thingValues[i],ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
b.append(_thingValues[i], ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
}
_issuedTo.appendTo(b);
_signedBy.appendTo(b);
if (!forSign) {
b.append((uint8_t)1); // 1 == Ed25519
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
if (! forSign) {
b.append((uint8_t)1); // 1 == Ed25519
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_signature.data, ZT_C25519_SIGNATURE_LEN);
}
b.append((uint16_t)0); // length of additional fields, currently 0
b.append((uint16_t)0); // length of additional fields, currently 0
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
unsigned int p = startAt;
@ -194,26 +210,27 @@ public:
p += 4;
_thingCount = b.template at<uint16_t>(p);
p += 2;
for(unsigned int i=0,j=_thingCount;i<j;++i) {
for (unsigned int i = 0, j = _thingCount; i < j; ++i) {
if (i < ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
_thingTypes[i] = (uint8_t)b[p++];
memcpy(_thingValues[i],b.field(p,ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE),ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
memcpy(_thingValues[i], b.field(p, ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE), ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
}
}
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
_issuedTo.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
_signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
}
p += 2;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
memcpy(_signature.data, b.field(p, ZT_C25519_SIGNATURE_LEN), ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else {
}
else {
p += 2 + b.template at<uint16_t>(p);
}
@ -226,13 +243,22 @@ public:
}
// Provides natural sort order by ID
inline bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); }
inline bool operator<(const CertificateOfOwnership& coo) const
{
return (_id < coo._id);
}
inline bool operator==(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); }
inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); }
inline bool operator==(const CertificateOfOwnership& coo) const
{
return (memcmp(this, &coo, sizeof(CertificateOfOwnership)) == 0);
}
inline bool operator!=(const CertificateOfOwnership& coo) const
{
return (memcmp(this, &coo, sizeof(CertificateOfOwnership)) != 0);
}
private:
bool _owns(const Thing &t,const void *v,unsigned int l) const;
private:
bool _owns(const Thing& t, const void* v, unsigned int l) const;
uint64_t _networkId;
int64_t _ts;
@ -246,6 +272,6 @@ private:
C25519::Signature _signature;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -61,8 +61,8 @@
#ifdef ZT_SSO_SUPPORTED
#define ZT_SSO_ENABLED 1
#endif
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#include <TargetConditionals.h>
#ifndef __UNIX_LIKE__
#define __UNIX_LIKE__
@ -85,9 +85,9 @@
#endif
#include <machine/endian.h>
#ifndef __BYTE_ORDER
#define __BYTE_ORDER _BYTE_ORDER
#define __BYTE_ORDER _BYTE_ORDER
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
#define __BIG_ENDIAN _BIG_ENDIAN
#define __BIG_ENDIAN _BIG_ENDIAN
#endif
#endif
@ -106,25 +106,25 @@
#pragma warning(disable : 4101)
#undef __UNIX_LIKE__
#undef __BSD__
#include <winsock2.h>
#include <windows.h>
#include <winsock2.h>
#endif
#ifdef __NetBSD__
#ifndef RTF_MULTICAST
#define RTF_MULTICAST 0x20000000
#define RTF_MULTICAST 0x20000000
#endif
#endif
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#define ZT_ARCH_X64 1
#include <xmmintrin.h>
#include <emmintrin.h>
#include <immintrin.h>
#include <xmmintrin.h>
#endif
#if (defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ZT_ARCH_ARM_HAS_NEON))
#if (defined(__APPLE__) && !defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__))
#if (defined(__APPLE__) && ! defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__))
#ifdef ZT_ARCH_ARM_HAS_NEON
#undef ZT_ARCH_ARM_HAS_NEON
#endif
@ -145,7 +145,8 @@
#endif
// Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86/x64.
#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
#if (! (defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) \
|| defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
#ifndef ZT_NO_TYPE_PUNNING
#define ZT_NO_TYPE_PUNNING 1
#endif
@ -157,23 +158,23 @@
#endif
// Assume little endian if not defined
#if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER))
#if (defined(__APPLE__) || defined(__WINDOWS__)) && (! defined(__BYTE_ORDER))
#undef __BYTE_ORDER
#undef __LITTLE_ENDIAN
#undef __BIG_ENDIAN
#define __BIG_ENDIAN 4321
#define __BIG_ENDIAN 4321
#define __LITTLE_ENDIAN 1234
#define __BYTE_ORDER 1234
#define __BYTE_ORDER 1234
#endif
#ifdef __WINDOWS__
#define ZT_PATH_SEPARATOR '\\'
#define ZT_PATH_SEPARATOR '\\'
#define ZT_PATH_SEPARATOR_S "\\"
#define ZT_EOL_S "\r\n"
#define ZT_EOL_S "\r\n"
#else
#define ZT_PATH_SEPARATOR '/'
#define ZT_PATH_SEPARATOR '/'
#define ZT_PATH_SEPARATOR_S "/"
#define ZT_EOL_S "\n"
#define ZT_EOL_S "\n"
#endif
#ifndef __BYTE_ORDER
@ -182,10 +183,10 @@
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
#ifndef likely
#define likely(x) __builtin_expect((x),1)
#define likely(x) __builtin_expect((x), 1)
#endif
#ifndef unlikely
#define unlikely(x) __builtin_expect((x),0)
#define unlikely(x) __builtin_expect((x), 0)
#endif
#else
#ifndef likely
@ -197,43 +198,43 @@
#endif
#ifdef __WINDOWS__
#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
#define ZT_PACKED_STRUCT(D) __pragma(pack(push, 1)) D __pragma(pack(pop))
#else
#define ZT_PACKED_STRUCT(D) D __attribute__((packed))
#endif
#if defined(_WIN32)
#define ZT_PLATFORM_NAME "windows" // Windows
#define ZT_PLATFORM_NAME "windows" // Windows
#elif defined(_WIN64)
#define ZT_PLATFORM_NAME "windows" // Windows
#define ZT_PLATFORM_NAME "windows" // Windows
#elif defined(__CYGWIN__)
#define ZT_PLATFORM_NAME "windows" // Windows (Cygwin POSIX under Microsoft Window)
#define ZT_PLATFORM_NAME "windows" // Windows (Cygwin POSIX under Microsoft Window)
#elif defined(__ANDROID__)
#define ZT_PLATFORM_NAME "android" // Android (implies Linux, so it must come first)
#define ZT_PLATFORM_NAME "android" // Android (implies Linux, so it must come first)
#elif defined(__linux__)
#define ZT_PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other
#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__)
#define ZT_PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other
#elif defined(__unix__) || ! defined(__APPLE__) && defined(__MACH__)
#include <sys/param.h>
#if defined(BSD)
#define ZT_PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD
#define ZT_PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD
#endif
#elif defined(__hpux)
#define ZT_PLATFORM_NAME "hp-ux" // HP-UX
#define ZT_PLATFORM_NAME "hp-ux" // HP-UX
#elif defined(_AIX)
#define ZT_PLATFORM_NAME "aix" // IBM AIX
#elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin)
#define ZT_PLATFORM_NAME "aix" // IBM AIX
#elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin)
#include <TargetConditionals.h>
#if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR == 1
#define ZT_PLATFORM_NAME "ios_sim" // Apple iOS
#define ZT_PLATFORM_NAME "ios_sim" // Apple iOS
#elif defined(TARGET_OS_IPAD) && TARGET_OS_IPAD == 1
#define ZT_PLATFORM_NAME "ios_ipad"
#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1
#define ZT_PLATFORM_NAME "ios_iphone" // Apple iOS
#define ZT_PLATFORM_NAME "ios_iphone" // Apple iOS
#elif defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1
#define ZT_PLATFORM_NAME "macos" // Apple OSX
#define ZT_PLATFORM_NAME "macos" // Apple OSX
#endif
#elif defined(__sun) && defined(__SVR4)
#define ZT_PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana
#define ZT_PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana
#else
#define ZT_PLATFORM_NAME "unknown"
#endif
@ -255,7 +256,7 @@
#define ZT_ARCH_NAME "mips"
#elif defined(__riscv) || defined(__riscv_xlen)
#define ZT_ARCH_NAME "riscv"
#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined (_M_PPC)
#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC)
#define ZT_ARCH_NAME "powerpc"
#elif defined(__s390__) || defined(__s390x__) || defined(__zarch__)
#define ZT_ARCH_NAME "s390"
@ -580,23 +581,23 @@
/**
* Drainage constants for VERB_ECHO rate-limiters
*/
#define ZT_ECHO_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS)
#define ZT_ECHO_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS)
#define ZT_ECHO_DRAINAGE_DIVISOR (1000 / ZT_ECHO_CUTOFF_LIMIT)
/**
* Drainage constants for VERB_QOS rate-limiters
*/
#define ZT_QOS_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS)
#define ZT_QOS_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS)
#define ZT_QOS_DRAINAGE_DIVISOR (1000 / ZT_QOS_CUTOFF_LIMIT)
/**
* Drainage constants for VERB_ACK rate-limiters
*/
#define ZT_ACK_CUTOFF_LIMIT 128
#define ZT_ACK_CUTOFF_LIMIT 128
#define ZT_ACK_DRAINAGE_DIVISOR (1000 / ZT_ACK_CUTOFF_LIMIT)
#define ZT_BOND_DEFAULT_REFRACTORY_PERIOD 8000
#define ZT_BOND_MAX_REFRACTORY_PERIOD 600000
#define ZT_BOND_MAX_REFRACTORY_PERIOD 600000
/**
* Maximum number of direct path pushes within cutoff time
@ -632,7 +633,6 @@
*/
#define ZT_PEER_GENERAL_RATE_LIMIT 1000
/**
* Minimum allowed amount of time between flow/path optimizations (anti-flapping)
*/
@ -709,8 +709,8 @@
* Artificially inflates the failover score for paths which meet
* certain non-performance-related policy ranking criteria.
*/
#define ZT_BOND_FAILOVER_HANDICAP_PREFERRED 500
#define ZT_BOND_FAILOVER_HANDICAP_PRIMARY 1000
#define ZT_BOND_FAILOVER_HANDICAP_PREFERRED 500
#define ZT_BOND_FAILOVER_HANDICAP_PRIMARY 1000
#define ZT_BOND_FAILOVER_HANDICAP_NEGOTIATED 5000
/**
@ -754,14 +754,14 @@
#define ZT_THREAD_MIN_STACK_SIZE 1048576
// Exceptions thrown in core ZT code
#define ZT_EXCEPTION_OUT_OF_BOUNDS 100
#define ZT_EXCEPTION_OUT_OF_MEMORY 101
#define ZT_EXCEPTION_PRIVATE_KEY_REQUIRED 102
#define ZT_EXCEPTION_INVALID_ARGUMENT 103
#define ZT_EXCEPTION_INVALID_IDENTITY 104
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE 200
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW 201
#define ZT_EXCEPTION_OUT_OF_BOUNDS 100
#define ZT_EXCEPTION_OUT_OF_MEMORY 101
#define ZT_EXCEPTION_PRIVATE_KEY_REQUIRED 102
#define ZT_EXCEPTION_INVALID_ARGUMENT 103
#define ZT_EXCEPTION_INVALID_IDENTITY 104
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE 200
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW 201
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN 202
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING 203
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING 203
#endif

View file

@ -14,39 +14,36 @@
#ifndef ZT_CREDENTIAL_HPP
#define ZT_CREDENTIAL_HPP
#include <string>
#include "Constants.hpp"
#include <memory>
#include <stdexcept>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "Constants.hpp"
#include <string>
namespace ZeroTier {
/**
* Base class for credentials
*/
class Credential
{
public:
class Credential {
public:
/**
* Do not change type code IDs -- these are used in Revocation objects and elsewhere
*/
enum Type
{
enum Type {
CREDENTIAL_TYPE_NULL = 0,
CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership
CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership
CREDENTIAL_TYPE_CAPABILITY = 2,
CREDENTIAL_TYPE_TAG = 3,
CREDENTIAL_TYPE_COO = 4, // CertificateOfOwnership
CREDENTIAL_TYPE_COO = 4, // CertificateOfOwnership
CREDENTIAL_TYPE_REVOCATION = 6
};
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -13,45 +13,43 @@
#ifndef ZT_DNS_HPP
#define ZT_DNS_HPP
#include "../include/ZeroTierOne.h"
#include "Buffer.hpp"
#include "InetAddress.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Buffer.hpp"
#include "InetAddress.hpp"
#include "../include/ZeroTierOne.h"
namespace ZeroTier {
/**
* DNS data serialization methods
*/
class DNS {
public:
template<unsigned int C>
static inline void serializeDNS(Buffer<C> &b, const ZT_VirtualNetworkDNS *dns)
{
b.append(dns->domain, 128);
for(unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
InetAddress tmp(dns->server_addr[j]);
tmp.serialize(b);
}
}
public:
template <unsigned int C> static inline void serializeDNS(Buffer<C>& b, const ZT_VirtualNetworkDNS* dns)
{
b.append(dns->domain, 128);
for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
InetAddress tmp(dns->server_addr[j]);
tmp.serialize(b);
}
}
template<unsigned int C>
static inline void deserializeDNS(const Buffer<C> &b, unsigned int &p, ZT_VirtualNetworkDNS *dns)
{
char *d = (char*)b.data()+p;
memset(dns, 0, sizeof(ZT_VirtualNetworkDNS));
memcpy(dns->domain, d, 128);
dns->domain[127] = 0;
p += 128;
for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
p += reinterpret_cast<InetAddress *>(&(dns->server_addr[j]))->deserialize(b, p);
}
}
template <unsigned int C> static inline void deserializeDNS(const Buffer<C>& b, unsigned int& p, ZT_VirtualNetworkDNS* dns)
{
char* d = (char*)b.data() + p;
memset(dns, 0, sizeof(ZT_VirtualNetworkDNS));
memcpy(dns->domain, d, 128);
dns->domain[127] = 0;
p += 128;
for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
p += reinterpret_cast<InetAddress*>(&(dns->server_addr[j]))->deserialize(b, p);
}
}
};
}
} // namespace ZeroTier
#endif // ZT_DNS_HPP
#endif // ZT_DNS_HPP

View file

@ -14,10 +14,10 @@
#ifndef ZT_DICTIONARY_HPP
#define ZT_DICTIONARY_HPP
#include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include "Address.hpp"
#include <stdint.h>
@ -45,36 +45,48 @@ namespace ZeroTier {
*
* @tparam C Dictionary max capacity in bytes
*/
template<unsigned int C>
class Dictionary
{
public:
Dictionary() { memset(_d,0,sizeof(_d)); }
Dictionary(const char *s) { this->load(s); }
Dictionary(const char *s,unsigned int len)
template <unsigned int C> class Dictionary {
public:
Dictionary()
{
for(unsigned int i=0;i<C;++i) {
if ((s)&&(i < len)) {
if (!(_d[i] = *s)) {
s = (const char *)0;
} else {
memset(_d, 0, sizeof(_d));
}
Dictionary(const char* s)
{
this->load(s);
}
Dictionary(const char* s, unsigned int len)
{
for (unsigned int i = 0; i < C; ++i) {
if ((s) && (i < len)) {
if (! (_d[i] = *s)) {
s = (const char*)0;
}
else {
++s;
}
} else {
}
else {
_d[i] = (char)0;
}
}
_d[C - 1] = (char)0;
}
Dictionary(const Dictionary &d) { memcpy(_d,d._d,C); }
inline Dictionary &operator=(const Dictionary &d)
Dictionary(const Dictionary& d)
{
memcpy(_d,d._d,C);
memcpy(_d, d._d, C);
}
inline Dictionary& operator=(const Dictionary& d)
{
memcpy(_d, d._d, C);
return *this;
}
inline operator bool() const { return (_d[0] != 0); }
inline operator bool() const
{
return (_d[0] != 0);
}
/**
* Load a dictionary from a C-string
@ -82,21 +94,23 @@ public:
* @param s Dictionary in string form
* @return False if 's' was longer than our capacity
*/
inline bool load(const char *s)
inline bool load(const char* s)
{
for(unsigned int i=0;i<C;++i) {
for (unsigned int i = 0; i < C; ++i) {
if (s) {
if (!(_d[i] = *s)) {
s = (const char *)0;
} else {
if (! (_d[i] = *s)) {
s = (const char*)0;
}
else {
++s;
}
} else {
}
else {
_d[i] = (char)0;
}
}
_d[C - 1] = (char)0;
return (!s);
return (! s);
}
/**
@ -104,7 +118,7 @@ public:
*/
inline void clear()
{
memset(_d,0,sizeof(_d));
memset(_d, 0, sizeof(_d));
}
/**
@ -112,12 +126,12 @@ public:
*/
inline unsigned int sizeBytes() const
{
for(unsigned int i=0;i<C;++i) {
if (!_d[i]) {
for (unsigned int i = 0; i < C; ++i) {
if (! _d[i]) {
return i;
}
}
return C-1;
return C - 1;
}
/**
@ -142,21 +156,21 @@ public:
* @param destlen Size of destination buffer
* @return -1 if not found, or actual number of bytes stored in dest[] minus trailing 0
*/
inline int get(const char *key,char *dest,unsigned int destlen) const
inline int get(const char* key, char* dest, unsigned int destlen) const
{
const char *p = _d;
const char *const eof = p + C;
const char *k;
const char* p = _d;
const char* const eof = p + C;
const char* k;
bool esc;
int j;
if (!destlen) { // sanity check
if (! destlen) { // sanity check
return -1;
}
while (*p) {
k = key;
while ((*k)&&(*p)) {
while ((*k) && (*p)) {
if (*p != *k) {
break;
}
@ -167,14 +181,14 @@ public:
}
}
if ((!*k)&&(*p == '=')) {
if ((! *k) && (*p == '=')) {
j = 0;
esc = false;
++p;
while ((*p != 0)&&(*p != 13)&&(*p != 10)) {
while ((*p != 0) && (*p != 13) && (*p != 10)) {
if (esc) {
esc = false;
switch(*p) {
switch (*p) {
case 'r':
dest[j++] = 13;
break;
@ -192,16 +206,18 @@ public:
break;
}
if (j == (int)destlen) {
dest[j-1] = (char)0;
return j-1;
dest[j - 1] = (char)0;
return j - 1;
}
} else if (*p == '\\') {
}
else if (*p == '\\') {
esc = true;
} else {
}
else {
dest[j++] = *p;
if (j == (int)destlen) {
dest[j-1] = (char)0;
return j-1;
dest[j - 1] = (char)0;
return j - 1;
}
}
if (++p == eof) {
@ -211,8 +227,9 @@ public:
}
dest[j] = (char)0;
return j;
} else {
while ((*p)&&(*p != 13)&&(*p != 10)) {
}
else {
while ((*p) && (*p != 13) && (*p != 10)) {
if (++p == eof) {
dest[0] = (char)0;
return -1;
@ -223,7 +240,8 @@ public:
dest[0] = (char)0;
return -1;
}
} else {
}
else {
break;
}
}
@ -241,14 +259,14 @@ public:
* @return True if key was found (if false, dest will be empty)
* @tparam BC Buffer capacity (usually inferred)
*/
template<unsigned int BC>
inline bool get(const char *key,Buffer<BC> &dest) const
template <unsigned int BC> inline bool get(const char* key, Buffer<BC>& dest) const
{
const int r = this->get(key,const_cast<char *>(reinterpret_cast<const char *>(dest.data())),BC);
const int r = this->get(key, const_cast<char*>(reinterpret_cast<const char*>(dest.data())), BC);
if (r >= 0) {
dest.setSize((unsigned int)r);
return true;
} else {
}
else {
dest.clear();
return false;
}
@ -261,11 +279,11 @@ public:
* @param dfl Default value if not found in dictionary
* @return Boolean value of key or 'dfl' if not found
*/
bool getB(const char *key,bool dfl = false) const
bool getB(const char* key, bool dfl = false) const
{
char tmp[4];
if (this->get(key,tmp,sizeof(tmp)) >= 0) {
return ((*tmp == '1')||(*tmp == 't')||(*tmp == 'T'));
if (this->get(key, tmp, sizeof(tmp)) >= 0) {
return ((*tmp == '1') || (*tmp == 't') || (*tmp == 'T'));
}
return dfl;
}
@ -277,10 +295,10 @@ public:
* @param dfl Default value or 0 if unspecified
* @return Decoded hex UInt value or 'dfl' if not found
*/
inline uint64_t getUI(const char *key,uint64_t dfl = 0) const
inline uint64_t getUI(const char* key, uint64_t dfl = 0) const
{
char tmp[128];
if (this->get(key,tmp,sizeof(tmp)) >= 1) {
if (this->get(key, tmp, sizeof(tmp)) >= 1) {
return Utils::hexStrToU64(tmp);
}
return dfl;
@ -293,10 +311,10 @@ public:
* @param dfl Default value or 0 if unspecified
* @return Decoded hex UInt value or 'dfl' if not found
*/
inline int64_t getI(const char *key,int64_t dfl = 0) const
inline int64_t getI(const char* key, int64_t dfl = 0) const
{
char tmp[128];
if (this->get(key,tmp,sizeof(tmp)) >= 1) {
if (this->get(key, tmp, sizeof(tmp)) >= 1) {
return Utils::hexStrTo64(tmp);
}
return dfl;
@ -316,10 +334,10 @@ public:
* @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0
* @return True if there was enough room to add this key=value pair
*/
inline bool add(const char *key,const char *value,int vlen = -1)
inline bool add(const char* key, const char* value, int vlen = -1)
{
for(unsigned int i=0;i<C;++i) {
if (!_d[i]) {
for (unsigned int i = 0; i < C; ++i) {
if (! _d[i]) {
unsigned int j = i;
if (j > 0) {
@ -330,7 +348,7 @@ public:
}
}
const char *p = key;
const char* p = key;
while (*p) {
_d[j++] = *(p++);
if (j == C) {
@ -347,8 +365,8 @@ public:
p = value;
int k = 0;
while ( ((vlen < 0)&&(*p)) || (k < vlen) ) {
switch(*p) {
while (((vlen < 0) && (*p)) || (k < vlen)) {
switch (*p) {
case 0:
case 13:
case 10:
@ -359,7 +377,7 @@ public:
_d[i] = (char)0;
return false;
}
switch(*p) {
switch (*p) {
case 0:
_d[j++] = '0';
break;
@ -404,41 +422,42 @@ public:
/**
* Add a boolean as a '1' or a '0'
*/
inline bool add(const char *key,bool value)
inline bool add(const char* key, bool value)
{
return this->add(key,(value) ? "1" : "0",1);
return this->add(key, (value) ? "1" : "0", 1);
}
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
inline bool add(const char *key,uint64_t value)
inline bool add(const char* key, uint64_t value)
{
char tmp[32];
return this->add(key,Utils::hex(value,tmp),-1);
return this->add(key, Utils::hex(value, tmp), -1);
}
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
inline bool add(const char *key,int64_t value)
inline bool add(const char* key, int64_t value)
{
char tmp[32];
if (value >= 0) {
return this->add(key,Utils::hex((uint64_t)value,tmp),-1);
} else {
return this->add(key, Utils::hex((uint64_t)value, tmp), -1);
}
else {
tmp[0] = '-';
return this->add(key,Utils::hex((uint64_t)(value * -1),tmp+1),-1);
return this->add(key, Utils::hex((uint64_t)(value * -1), tmp + 1), -1);
}
}
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
inline bool add(const char *key,const Address &a)
inline bool add(const char* key, const Address& a)
{
char tmp[32];
return this->add(key,Utils::hex(a.toInt(),tmp),-1);
return this->add(key, Utils::hex(a.toInt(), tmp), -1);
}
/**
@ -446,34 +465,42 @@ public:
*
* @tparam BC Buffer capacity (usually inferred)
*/
template<unsigned int BC>
inline bool add(const char *key,const Buffer<BC> &value)
template <unsigned int BC> inline bool add(const char* key, const Buffer<BC>& value)
{
return this->add(key,(const char *)value.data(),(int)value.size());
return this->add(key, (const char*)value.data(), (int)value.size());
}
/**
* @param key Key to check
* @return True if key is present
*/
inline bool contains(const char *key) const
inline bool contains(const char* key) const
{
char tmp[2];
return (this->get(key,tmp,2) >= 0);
return (this->get(key, tmp, 2) >= 0);
}
/**
* @return Value of C template parameter
*/
inline unsigned int capacity() const { return C; }
inline unsigned int capacity() const
{
return C;
}
inline const char *data() const { return _d; }
inline char *unsafeData() { return _d; }
inline const char* data() const
{
return _d;
}
inline char* unsafeData()
{
return _d;
}
private:
private:
char _d[C];
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -16,36 +16,43 @@
#include "Constants.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdexcept>
#include <vector>
#include <utility>
#include <algorithm>
#include <vector>
namespace ZeroTier {
/**
* A minimal hash table implementation for the ZeroTier core
*/
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; }
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
_Bucket* next; // must be set manually for each _Bucket
};
public:
public:
/**
* A simple forward iterator (different from STL)
*
@ -53,16 +60,12 @@ public:
* may rehash and invalidate the iterator. Note the erasing the key will destroy
* the targets of the pointers returned by next().
*/
class Iterator
{
public:
class Iterator {
public:
/**
* @param ht Hash table to iterate over
*/
Iterator(Hashtable &ht) :
_idx(0),
_ht(&ht),
_b(ht._t[0])
Iterator(Hashtable& ht) : _idx(0), _ht(&ht), _b(ht._t[0])
{
}
@ -71,9 +74,9 @@ public:
* @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)
inline bool next(K*& kptr, V*& vptr)
{
for(;;) {
for (;;) {
if (_b) {
kptr = &(_b->k);
vptr = &(_b->v);
@ -88,44 +91,38 @@ public:
}
}
private:
private:
unsigned long _idx;
Hashtable *_ht;
_Bucket *_b;
Hashtable* _ht;
_Bucket* _b;
};
//friend class Hashtable<K,V>::Iterator;
// friend class Hashtable<K,V>::Iterator;
/**
* @param bc Initial capacity in buckets (default: 64, must be nonzero)
*/
Hashtable(unsigned long bc = 64) :
_t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * bc))),
_bc(bc),
_s(0)
Hashtable(unsigned long bc = 64) : _t(reinterpret_cast<_Bucket**>(::malloc(sizeof(_Bucket*) * bc))), _bc(bc), _s(0)
{
if (!_t) {
if (! _t) {
throw ZT_EXCEPTION_OUT_OF_MEMORY;
}
for(unsigned long i=0;i<bc;++i) {
_t[i] = (_Bucket *)0;
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)
Hashtable(const Hashtable<K, V>& ht) : _t(reinterpret_cast<_Bucket**>(::malloc(sizeof(_Bucket*) * ht._bc))), _bc(ht._bc), _s(ht._s)
{
if (!_t) {
if (! _t) {
throw ZT_EXCEPTION_OUT_OF_MEMORY;
}
for(unsigned long i=0;i<_bc;++i) {
_t[i] = (_Bucket *)0;
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];
for (unsigned long i = 0; i < _bc; ++i) {
const _Bucket* b = ht._t[i];
while (b) {
_Bucket *nb = new _Bucket(*b);
_Bucket* nb = new _Bucket(*b);
nb->next = _t[i];
_t[i] = nb;
b = b->next;
@ -139,14 +136,14 @@ public:
::free(_t);
}
inline Hashtable &operator=(const Hashtable<K,V> &ht)
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];
for (unsigned long i = 0; i < ht._bc; ++i) {
const _Bucket* b = ht._t[i];
while (b) {
this->set(b->k,b->v);
this->set(b->k, b->v);
b = b->next;
}
}
@ -160,14 +157,14 @@ public:
inline void clear()
{
if (_s) {
for(unsigned long i=0;i<_bc;++i) {
_Bucket *b = _t[i];
for (unsigned long i = 0; i < _bc; ++i) {
_Bucket* b = _t[i];
while (b) {
_Bucket *const nb = b->next;
_Bucket* const nb = b->next;
delete b;
b = nb;
}
_t[i] = (_Bucket *)0;
_t[i] = (_Bucket*)0;
}
_s = 0;
}
@ -181,8 +178,8 @@ public:
typename std::vector<K> k;
if (_s) {
k.reserve(_s);
for(unsigned long i=0;i<_bc;++i) {
_Bucket *b = _t[i];
for (unsigned long i = 0; i < _bc; ++i) {
_Bucket* b = _t[i];
while (b) {
k.push_back(b->k);
b = b->next;
@ -198,12 +195,11 @@ public:
* @param v Vector, list, or other compliant container
* @tparam Type of V (generally inferred)
*/
template<typename C>
inline void appendKeys(C &v) const
template <typename C> inline void appendKeys(C& v) const
{
if (_s) {
for(unsigned long i=0;i<_bc;++i) {
_Bucket *b = _t[i];
for (unsigned long i = 0; i < _bc; ++i) {
_Bucket* b = _t[i];
while (b) {
v.push_back(b->k);
b = b->next;
@ -215,15 +211,15 @@ public:
/**
* @return Vector of all entries (pairs of K,V)
*/
inline typename std::vector< std::pair<K,V> > entries() const
inline typename std::vector<std::pair<K, V> > entries() const
{
typename std::vector< std::pair<K,V> > k;
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];
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));
k.push_back(std::pair<K, V>(b->k, b->v));
b = b->next;
}
}
@ -235,27 +231,30 @@ public:
* @param k Key
* @return Pointer to value or NULL if not found
*/
inline V *get(const K &k)
inline V* get(const K& k)
{
_Bucket *b = _t[_hc(k) % _bc];
_Bucket* b = _t[_hc(k) % _bc];
while (b) {
if (b->k == k) {
return &(b->v);
}
b = b->next;
}
return (V *)0;
return (V*)0;
}
inline const V* get(const K& k) const
{
return const_cast<Hashtable*>(this)->get(k);
}
inline const V *get(const K &k) const { return const_cast<Hashtable *>(this)->get(k); }
/**
* @param k Key
* @param v Value to fill with result
* @return True if value was found and set (if false, v is not modified)
*/
inline bool get(const K &k,V &v) const
inline bool get(const K& k, V& v) const
{
_Bucket *b = _t[_hc(k) % _bc];
_Bucket* b = _t[_hc(k) % _bc];
while (b) {
if (b->k == k) {
v = b->v;
@ -270,9 +269,9 @@ public:
* @param k Key to check
* @return True if key is present
*/
inline bool contains(const K &k) const
inline bool contains(const K& k) const
{
_Bucket *b = _t[_hc(k) % _bc];
_Bucket* b = _t[_hc(k) % _bc];
while (b) {
if (b->k == k) {
return true;
@ -286,16 +285,17 @@ public:
* @param k Key
* @return True if value was present
*/
inline bool erase(const K &k)
inline bool erase(const K& k)
{
const unsigned long bidx = _hc(k) % _bc;
_Bucket *lastb = (_Bucket *)0;
_Bucket *b = _t[bidx];
_Bucket* lastb = (_Bucket*)0;
_Bucket* b = _t[bidx];
while (b) {
if (b->k == k) {
if (lastb) {
lastb->next = b->next;
} else {
}
else {
_t[bidx] = b->next;
}
delete b;
@ -313,12 +313,12 @@ public:
* @param v Value
* @return Reference to value in table
*/
inline V &set(const K &k,const V &v)
inline V& set(const K& k, const V& v)
{
const unsigned long h = _hc(k);
unsigned long bidx = h % _bc;
_Bucket *b = _t[bidx];
_Bucket* b = _t[bidx];
while (b) {
if (b->k == k) {
b->v = v;
@ -332,7 +332,7 @@ public:
bidx = h % _bc;
}
b = new _Bucket(k,v);
b = new _Bucket(k, v);
b->next = _t[bidx];
_t[bidx] = b;
++_s;
@ -343,12 +343,12 @@ public:
* @param k Key
* @return Value, possibly newly created
*/
inline V &operator[](const K &k)
inline V& operator[](const K& k)
{
const unsigned long h = _hc(k);
unsigned long bidx = h % _bc;
_Bucket *b = _t[bidx];
_Bucket* b = _t[bidx];
while (b) {
if (b->k == k) {
return b->v;
@ -371,22 +371,27 @@ public:
/**
* @return Number of entries
*/
inline unsigned long size() const { return _s; }
inline unsigned long size() const
{
return _s;
}
/**
* @return True if table is empty
*/
inline bool empty() const { return (_s == 0); }
inline bool empty() const
{
return (_s == 0);
}
private:
template<typename O>
static inline unsigned long _hc(const O &obj)
private:
template <typename O> static inline unsigned long _hc(const O& obj)
{
return (unsigned long)obj.hashCode();
}
static inline unsigned long _hc(const uint64_t i)
{
return (unsigned long)(i ^ (i >> 32)); // good for network IDs and addresses
return (unsigned long)(i ^ (i >> 32)); // good for network IDs and addresses
}
static inline unsigned long _hc(const uint32_t i)
{
@ -404,15 +409,15 @@ private:
inline void _grow()
{
const unsigned long nc = _bc * 2;
_Bucket **nt = reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * nc));
_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 < nc; ++i) {
nt[i] = (_Bucket*)0;
}
for(unsigned long i=0;i<_bc;++i) {
_Bucket *b = _t[i];
for (unsigned long i = 0; i < _bc; ++i) {
_Bucket* b = _t[i];
while (b) {
_Bucket *const nb = b->next;
_Bucket* const nb = b->next;
const unsigned long nidx = _hc(b->k) % nc;
b->next = nt[nidx];
nt[nidx] = b;
@ -425,11 +430,11 @@ private:
}
}
_Bucket **_t;
_Bucket** _t;
unsigned long _bc;
unsigned long _s;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,94 +11,98 @@
*/
/****/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "Identity.hpp"
#include "Constants.hpp"
#include "Identity.hpp"
#include "SHA512.hpp"
#include "Salsa20.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 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
#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)
static inline void _computeMemoryHardHash(const void* publicKey, unsigned int publicKeyBytes, void* digest, void* genmem)
{
// Digest publicKey[] to obtain initial digest
SHA512(digest,publicKey,publicKeyBytes);
SHA512(digest, publicKey, publicKeyBytes);
// Initialize genmem[] using Salsa20 in a CBC-like configuration since
// ordinary Salsa20 is randomly seek-able. This is good for a cipher
// but is not what we want for sequential memory-hardness.
memset(genmem,0,ZT_IDENTITY_GEN_MEMORY);
Salsa20 s20(digest,(char *)digest + 32);
s20.crypt20((char *)genmem,(char *)genmem,64);
for(unsigned long i=64;i<ZT_IDENTITY_GEN_MEMORY;i+=64) {
memset(genmem, 0, ZT_IDENTITY_GEN_MEMORY);
Salsa20 s20(digest, (char*)digest + 32);
s20.crypt20((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.crypt20((char *)genmem + i,(char *)genmem + 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.crypt20((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.crypt20(digest,digest,64);
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.crypt20(digest, digest, 64);
}
}
// Hashcash generation halting condition -- halt when first byte is less than
// threshold value.
struct _Identity_generate_cond
{
_Identity_generate_cond() {}
_Identity_generate_cond(unsigned char *sb,char *gm) : digest(sb),genmem(gm) {}
inline bool operator()(const C25519::Pair &kp) const
struct _Identity_generate_cond {
_Identity_generate_cond()
{
_computeMemoryHardHash(kp.pub.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
}
_Identity_generate_cond(unsigned char* sb, char* gm) : digest(sb), genmem(gm)
{
}
inline bool operator()(const C25519::Pair& kp) const
{
_computeMemoryHardHash(kp.pub.data, ZT_C25519_PUBLIC_KEY_LEN, digest, genmem);
return (digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN);
}
unsigned char *digest;
char *genmem;
unsigned char* digest;
char* genmem;
};
void Identity::generate()
{
unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
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
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) {
if (! _privateKey) {
_privateKey = new C25519::Private();
}
*_privateKey = kp.priv;
delete [] genmem;
delete[] genmem;
}
bool Identity::locallyValidate() const
@ -108,60 +112,54 @@ bool Identity::locallyValidate() const
}
unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
_computeMemoryHardHash(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
delete [] genmem;
char* genmem = new char[ZT_IDENTITY_GEN_MEMORY];
_computeMemoryHardHash(_publicKey.data, ZT_C25519_PUBLIC_KEY_LEN, digest, genmem);
delete[] genmem;
unsigned char addrb[5];
_address.copyTo(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]));
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]));
}
char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
char* Identity::toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
{
char *p = buf;
Utils::hex10(_address.toInt(),p);
char* p = buf;
Utils::hex10(_address.toInt(), p);
p += 10;
*(p++) = ':';
*(p++) = '0';
*(p++) = ':';
Utils::hex(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN,p);
Utils::hex(_publicKey.data, ZT_C25519_PUBLIC_KEY_LEN, p);
p += ZT_C25519_PUBLIC_KEY_LEN * 2;
if ((_privateKey)&&(includePrivate)) {
if ((_privateKey) && (includePrivate)) {
*(p++) = ':';
Utils::hex(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN,p);
Utils::hex(_privateKey->data, ZT_C25519_PRIVATE_KEY_LEN, p);
p += ZT_C25519_PRIVATE_KEY_LEN * 2;
}
*p = (char)0;
return buf;
}
bool Identity::fromString(const char *str)
bool Identity::fromString(const char* str)
{
if (!str) {
if (! str) {
_address.zero();
return false;
}
char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH];
if (!Utils::scopy(tmp,sizeof(tmp),str)) {
if (! Utils::scopy(tmp, sizeof(tmp), str)) {
_address.zero();
return false;
}
delete _privateKey;
_privateKey = (C25519::Private *)0;
_privateKey = (C25519::Private*)0;
int fno = 0;
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp,":",&saveptr);(f);f=Utils::stok((char *)0,":",&saveptr)) {
switch(fno++) {
char* saveptr = (char*)0;
for (char* f = Utils::stok(tmp, ":", &saveptr); (f); f = Utils::stok((char*)0, ":", &saveptr)) {
switch (fno++) {
case 0:
_address = Address(Utils::hexStrToU64(f));
if (_address.isReserved()) {
@ -170,20 +168,20 @@ bool Identity::fromString(const char *str)
}
break;
case 1:
if ((f[0] != '0')||(f[1])) {
if ((f[0] != '0') || (f[1])) {
_address.zero();
return false;
}
break;
case 2:
if (Utils::unhex(f,_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
if (Utils::unhex(f, _publicKey.data, ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
_address.zero();
return false;
}
break;
case 3:
_privateKey = new C25519::Private();
if (Utils::unhex(f,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
if (Utils::unhex(f, _privateKey->data, ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
_address.zero();
return false;
}
@ -201,4 +199,4 @@ bool Identity::fromString(const char *str)
return true;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,16 +14,16 @@
#ifndef ZT_IDENTITY_HPP
#define ZT_IDENTITY_HPP
#include "Address.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
#include "Constants.hpp"
#include "SHA512.hpp"
#include "Utils.hpp"
#include <stdio.h>
#include <stdlib.h>
#include "Constants.hpp"
#include "Utils.hpp"
#include "Address.hpp"
#include "C25519.hpp"
#include "Buffer.hpp"
#include "SHA512.hpp"
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 384
namespace ZeroTier {
@ -38,56 +38,49 @@ namespace ZeroTier {
* search for a different public key that duplicates an existing address. (See
* code for deriveAddress() for this algorithm.)
*/
class Identity
{
public:
Identity() :
_privateKey((C25519::Private *)0)
class Identity {
public:
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 Identity& id) : _address(id._address), _publicKey(id._publicKey), _privateKey((id._privateKey) ? new C25519::Private(*(id._privateKey)) : (C25519::Private*)0)
{
}
Identity(const char *str) :
_privateKey((C25519::Private *)0)
Identity(const char* str) : _privateKey((C25519::Private*)0)
{
if (!fromString(str)) {
if (! fromString(str)) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
}
}
template<unsigned int C>
Identity(const Buffer<C> &b,unsigned int startAt = 0) :
_privateKey((C25519::Private *)0)
template <unsigned int C> Identity(const Buffer<C>& b, unsigned int startAt = 0) : _privateKey((C25519::Private*)0)
{
deserialize(b,startAt);
deserialize(b, startAt);
}
~Identity()
{
if (_privateKey) {
Utils::burn(_privateKey,sizeof(C25519::Private));
Utils::burn(_privateKey, sizeof(C25519::Private));
delete _privateKey;
}
}
inline Identity &operator=(const Identity &id)
inline Identity& operator=(const Identity& id)
{
_address = id._address;
_publicKey = id._publicKey;
if (id._privateKey) {
if (!_privateKey) {
if (! _privateKey) {
_privateKey = new C25519::Private();
}
*_privateKey = *(id._privateKey);
} else {
}
else {
delete _privateKey;
_privateKey = (C25519::Private *)0;
_privateKey = (C25519::Private*)0;
}
return *this;
}
@ -109,14 +102,17 @@ public:
/**
* @return True if this identity contains a private key
*/
inline bool hasPrivate() const { return (_privateKey != (C25519::Private *)0); }
inline bool hasPrivate() const
{
return (_privateKey != (C25519::Private*)0);
}
/**
* Compute a SHA384 hash of this identity's address and public key(s).
*
*
* @param sha384buf Buffer with 48 bytes of space to receive hash
*/
inline void publicKeyHash(void *sha384buf) const
inline void publicKeyHash(void* sha384buf) const
{
uint8_t address[ZT_ADDRESS_LENGTH];
_address.copyTo(address, ZT_ADDRESS_LENGTH);
@ -129,10 +125,10 @@ public:
* @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
inline bool sha512PrivateKey(void* sha) const
{
if (_privateKey) {
SHA512(sha,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN);
SHA512(sha, _privateKey->data, ZT_C25519_PRIVATE_KEY_LEN);
return true;
}
return false;
@ -144,10 +140,10 @@ public:
* @param data Data to sign
* @param len Length of data
*/
inline C25519::Signature sign(const void *data,unsigned int len) const
inline C25519::Signature sign(const void* data, unsigned int len) const
{
if (_privateKey) {
return C25519::sign(*_privateKey,_publicKey,data,len);
return C25519::sign(*_privateKey, _publicKey, data, len);
}
throw ZT_EXCEPTION_PRIVATE_KEY_REQUIRED;
}
@ -161,12 +157,12 @@ public:
* @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
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);
return C25519::verify(_publicKey, data, len, signature);
}
/**
@ -177,9 +173,9 @@ public:
* @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
inline bool verify(const void* data, unsigned int len, const C25519::Signature& signature) const
{
return C25519::verify(_publicKey,data,len,signature);
return C25519::verify(_publicKey, data, len, signature);
}
/**
@ -191,10 +187,10 @@ public:
* @param key Result parameter to fill with key bytes
* @return Was agreement successful?
*/
inline bool agree(const Identity &id,void *const key) const
inline bool agree(const Identity& id, void* const key) const
{
if (_privateKey) {
C25519::agree(*_privateKey,id._publicKey,key,ZT_SYMMETRIC_KEY_SIZE);
C25519::agree(*_privateKey, id._publicKey, key, ZT_SYMMETRIC_KEY_SIZE);
return true;
}
return false;
@ -203,7 +199,10 @@ public:
/**
* @return This identity's address
*/
inline const Address &address() const { return _address; }
inline const Address& address() const
{
return _address;
}
/**
* Serialize this identity (binary)
@ -212,16 +211,16 @@ public:
* @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
template <unsigned int C> inline void serialize(Buffer<C>& b, bool includePrivate = false) const
{
_address.appendTo(b);
b.append((uint8_t)0); // C25519/Ed25519 identity type
b.append(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN);
if ((_privateKey)&&(includePrivate)) {
b.append((uint8_t)0); // C25519/Ed25519 identity type
b.append(_publicKey.data, ZT_C25519_PUBLIC_KEY_LEN);
if ((_privateKey) && (includePrivate)) {
b.append((unsigned char)ZT_C25519_PRIVATE_KEY_LEN);
b.append(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN);
} else {
b.append(_privateKey->data, ZT_C25519_PRIVATE_KEY_LEN);
}
else {
b.append((unsigned char)0);
}
}
@ -238,22 +237,21 @@ public:
* @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)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
delete _privateKey;
_privateKey = (C25519::Private *)0;
_privateKey = (C25519::Private*)0;
unsigned int p = startAt;
_address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
_address.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (b[p++] != 0) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
}
memcpy(_publicKey.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
memcpy(_publicKey.data, b.field(p, ZT_C25519_PUBLIC_KEY_LEN), ZT_C25519_PUBLIC_KEY_LEN);
p += ZT_C25519_PUBLIC_KEY_LEN;
unsigned int privateKeyLength = (unsigned int)b[p++];
@ -262,7 +260,7 @@ public:
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
}
_privateKey = new C25519::Private();
memcpy(_privateKey->data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
memcpy(_privateKey->data, b.field(p, ZT_C25519_PRIVATE_KEY_LEN), ZT_C25519_PRIVATE_KEY_LEN);
p += ZT_C25519_PRIVATE_KEY_LEN;
}
@ -276,7 +274,7 @@ public:
* @param buf Buffer to store string
* @return ASCII string representation of identity
*/
char *toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const;
char* toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const;
/**
* Deserialize a human-friendly string
@ -287,12 +285,15 @@ public:
* @param str String to deserialize
* @return True if deserialization appears successful
*/
bool fromString(const char *str);
bool fromString(const char* str);
/**
* @return C25519 public key
*/
inline const C25519::Public &publicKey() const { return _publicKey; }
inline const C25519::Public& publicKey() const
{
return _publicKey;
}
/**
* @return C25519 key pair (only returns valid pair if private key is present in this Identity object)
@ -303,8 +304,9 @@ public:
pair.pub = _publicKey;
if (_privateKey) {
pair.priv = *_privateKey;
} else {
memset(pair.priv.data,0,ZT_C25519_PRIVATE_KEY_LEN);
}
else {
memset(pair.priv.data, 0, ZT_C25519_PRIVATE_KEY_LEN);
}
return pair;
}
@ -312,21 +314,42 @@ public:
/**
* @return True if this identity contains something
*/
inline operator bool() const { return (_address); }
inline operator bool() const
{
return (_address);
}
inline bool operator==(const Identity &id) const { return ((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) == 0)); }
inline bool operator<(const Identity &id) const { return ((_address < id._address)||((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) < 0))); }
inline bool operator!=(const Identity &id) const { return !(*this == id); }
inline bool operator>(const Identity &id) const { return (id < *this); }
inline bool operator<=(const Identity &id) const { return !(id < *this); }
inline bool operator>=(const Identity &id) const { return !(*this < id); }
inline bool operator==(const Identity& id) const
{
return ((_address == id._address) && (memcmp(_publicKey.data, id._publicKey.data, ZT_C25519_PUBLIC_KEY_LEN) == 0));
}
inline bool operator<(const Identity& id) const
{
return ((_address < id._address) || ((_address == id._address) && (memcmp(_publicKey.data, id._publicKey.data, ZT_C25519_PUBLIC_KEY_LEN) < 0)));
}
inline bool operator!=(const Identity& id) const
{
return ! (*this == id);
}
inline bool operator>(const Identity& id) const
{
return (id < *this);
}
inline bool operator<=(const Identity& id) const
{
return ! (id < *this);
}
inline bool operator>=(const Identity& id) const
{
return ! (*this < id);
}
private:
private:
Address _address;
C25519::Public _publicKey;
C25519::Private *_privateKey;
C25519::Private* _privateKey;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,13 +14,13 @@
#ifndef ZT_INCOMINGPACKET_HPP
#define ZT_INCOMINGPACKET_HPP
#include <stdexcept>
#include "MulticastGroup.hpp"
#include "Packet.hpp"
#include "Path.hpp"
#include "Utils.hpp"
#include "MulticastGroup.hpp"
#include "Peer.hpp"
#include "Utils.hpp"
#include <stdexcept>
/*
* The big picture:
@ -46,14 +46,9 @@ class Network;
/**
* Subclass of packet that handles the decoding of it
*/
class IncomingPacket : public Packet
{
public:
IncomingPacket() :
Packet(),
_receiveTime(0),
_path(),
_authenticated(false)
class IncomingPacket : public Packet {
public:
IncomingPacket() : Packet(), _receiveTime(0), _path(), _authenticated(false)
{
}
@ -66,11 +61,7 @@ public:
* @param now Current time
* @throws std::out_of_range Range error processing packet
*/
IncomingPacket(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now) :
Packet(data,len),
_receiveTime(now),
_path(path),
_authenticated(false)
IncomingPacket(const void* data, unsigned int len, const SharedPtr<Path>& path, int64_t now) : Packet(data, len), _receiveTime(now), _path(path), _authenticated(false)
{
}
@ -83,9 +74,9 @@ public:
* @param now Current time
* @throws std::out_of_range Range error processing packet
*/
inline void init(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now)
inline void init(const void* data, unsigned int len, const SharedPtr<Path>& path, int64_t now)
{
copyFrom(data,len);
copyFrom(data, len);
_receiveTime = now;
_path = path;
_authenticated = false;
@ -104,44 +95,47 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return True if decoding and processing is complete, false if caller should try again
*/
bool tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t flowId);
bool tryDecode(const RuntimeEnvironment* RR, void* tPtr, int32_t flowId);
/**
* @return Time of packet receipt / start of decode
*/
inline uint64_t receiveTime() const { return _receiveTime; }
inline uint64_t receiveTime() const
{
return _receiveTime;
}
private:
private:
// These are called internally to handle packet contents once it has
// been authenticated, decrypted, decompressed, and classified.
bool _doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated);
bool _doACK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doQOS_MEASUREMENT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,int32_t flowId);
bool _doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,int32_t flowId);
bool _doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doERROR(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doHELLO(const RuntimeEnvironment* RR, void* tPtr, const bool alreadyAuthenticated);
bool _doACK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doQOS_MEASUREMENT(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doOK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doWHOIS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doRENDEZVOUS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doFRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer, int32_t flowId);
bool _doEXT_FRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer, int32_t flowId);
bool _doECHO(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doMULTICAST_LIKE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doNETWORK_CONFIG(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doMULTICAST_GATHER(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doUSER_MESSAGE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doREMOTE_TRACE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid);
void _sendErrorNeedCredentials(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer, const uint64_t nwid);
uint64_t _receiveTime;
SharedPtr<Path> _path;
bool _authenticated;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,132 +11,132 @@
*/
/****/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <string>
#include "InetAddress.hpp"
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
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);
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
{
switch(ss_family) {
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) {
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)
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)
return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army)
case 0x0a:
return IP_SCOPE_PRIVATE; // 10.0.0.0/8
return IP_SCOPE_PRIVATE; // 10.0.0.0/8
case 0x0b:
return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
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)
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)
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)
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)
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)
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)
return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
case 0x1e:
return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
case 0x33:
return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security)
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)
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)
return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service)
case 0x64:
if ((ip & 0xffc00000) == 0x64400000) {
return IP_SCOPE_PRIVATE; // 100.64.0.0/10
return IP_SCOPE_PRIVATE; // 100.64.0.0/10
}
break;
case 0x7f:
return IP_SCOPE_LOOPBACK; // 127.0.0.0/8
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
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
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
return IP_SCOPE_PRIVATE; // 192.168.0.0/16
}
if ((ip & 0xffffff00) == 0xc0000200) {
return IP_SCOPE_PRIVATE; // 192.0.2.0/24
return IP_SCOPE_PRIVATE; // 192.0.2.0/24
}
break;
case 0xc6:
if ((ip & 0xfffe0000) == 0xc6120000) {
return IP_SCOPE_PRIVATE; // 198.18.0.0/15
return IP_SCOPE_PRIVATE; // 198.18.0.0/15
}
if ((ip & 0xffffff00) == 0xc6336400) {
return IP_SCOPE_PRIVATE; // 198.51.100.0/24
return IP_SCOPE_PRIVATE; // 198.51.100.0/24
}
break;
case 0xcb:
if ((ip & 0xffffff00) == 0xcb007100) {
return IP_SCOPE_PRIVATE; // 203.0.113.0/24
return IP_SCOPE_PRIVATE; // 203.0.113.0/24
}
break;
case 0xff:
return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
}
switch(ip >> 28) {
switch (ip >> 28) {
case 0xe:
return IP_SCOPE_MULTICAST; // 224.0.0.0/4
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_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable)
}
return IP_SCOPE_GLOBAL;
} break;
} break;
case AF_INET6: {
const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
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
return IP_SCOPE_MULTICAST; // ff00::/8
}
if ((ip[0] == 0xfe)&&((ip[1] & 0xc0) == 0x80)) {
if ((ip[0] == 0xfe) && ((ip[1] & 0xc0) == 0x80)) {
unsigned int k = 2;
while ((!ip[k])&&(k < 15)) {
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 ((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
return IP_SCOPE_PRIVATE; // fc00::/7
}
}
// :::ffff:127.0.0.1
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1
unsigned int k = 0;
while ((!ip[k])&&(k < 9)) {
while ((! ip[k]) && (k < 9)) {
++k;
}
if (k == 9) {
@ -146,92 +146,92 @@ InetAddress::IpScope InetAddress::ipScope() const
}
k = 0;
while ((!ip[k])&&(k < 15)) {
while ((! ip[k]) && (k < 15)) {
++k;
}
if (k == 15) { // all 0's except last byte
if (k == 15) { // all 0's except last byte
if (ip[15] == 0x01) {
return IP_SCOPE_LOOPBACK; // ::1/128
return IP_SCOPE_LOOPBACK; // ::1/128
}
if (ip[15] == 0x00) {
return IP_SCOPE_NONE; // ::/128
return IP_SCOPE_NONE; // ::/128
}
}
return IP_SCOPE_GLOBAL;
} break;
} break;
}
return IP_SCOPE_NONE;
}
void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port)
void InetAddress::set(const void* ipBytes, unsigned int ipLen, unsigned int port)
{
memset(this,0,sizeof(InetAddress));
memset(this, 0, sizeof(InetAddress));
if (ipLen == 4) {
uint32_t ipb[1];
memcpy(ipb,ipBytes,4);
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) {
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);
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);
}
}
char *InetAddress::toString(char buf[64]) const
char* InetAddress::toString(char buf[64]) const
{
char *p = toIpString(buf);
char* p = toIpString(buf);
if (*p) {
while (*p) {
++p;
}
*(p++) = '/';
Utils::decimal(port(),p);
Utils::decimal(port(), p);
}
return buf;
}
char *InetAddress::toIpString(char buf[64]) const
char* InetAddress::toIpString(char buf[64]) const
{
buf[0] = (char)0;
switch(ss_family) {
switch (ss_family) {
case AF_INET: {
#ifdef _WIN32
inet_ntop(AF_INET, (void*)&reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
inet_ntop(AF_INET, (void*)&reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
#else
inet_ntop(AF_INET, &reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
#endif
} break;
} break;
case AF_INET6: {
#ifdef _WIN32
inet_ntop(AF_INET6, (void*)reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, (void*)reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
#else
inet_ntop(AF_INET6, reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
#endif
} break;
} break;
}
return buf;
}
bool InetAddress::fromString(const char *ipSlashPort)
bool InetAddress::fromString(const char* ipSlashPort)
{
char buf[64];
memset(this,0,sizeof(InetAddress));
memset(this, 0, sizeof(InetAddress));
if (!*ipSlashPort) {
if (! *ipSlashPort) {
return true;
}
if (!Utils::scopy(buf,sizeof(buf),ipSlashPort)) {
if (! Utils::scopy(buf, sizeof(buf), ipSlashPort)) {
return false;
}
char *portAt = buf;
while ((*portAt)&&(*portAt != '/')) {
char* portAt = buf;
while ((*portAt) && (*portAt != '/')) {
++portAt;
}
unsigned int port = 0;
@ -240,19 +240,21 @@ bool InetAddress::fromString(const char *ipSlashPort)
port = Utils::strToUInt(portAt) & 0xffff;
}
if (strchr(buf,':')) {
struct sockaddr_in6 *const in6 = reinterpret_cast<struct sockaddr_in6 *>(this);
if (strchr(buf, ':')) {
struct sockaddr_in6* const in6 = reinterpret_cast<struct sockaddr_in6*>(this);
inet_pton(AF_INET6, buf, &in6->sin6_addr.s6_addr);
in6->sin6_family = AF_INET6;
in6->sin6_port = Utils::hton((uint16_t)port);
return true;
} else if (strchr(buf,'.')) {
struct sockaddr_in *const in = reinterpret_cast<struct sockaddr_in *>(this);
}
else if (strchr(buf, '.')) {
struct sockaddr_in* const in = reinterpret_cast<struct sockaddr_in*>(this);
inet_pton(AF_INET, buf, &in->sin_addr.s_addr);
in->sin_family = AF_INET;
in->sin_port = Utils::hton((uint16_t)port);
return true;
} else {
}
else {
return false;
}
}
@ -260,22 +262,23 @@ bool InetAddress::fromString(const char *ipSlashPort)
InetAddress InetAddress::netmask() const
{
InetAddress r(*this);
switch(r.ss_family) {
switch (r.ss_family) {
case AF_INET:
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
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();
if(bits) {
if (bits) {
nm[0] = Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
} else {
}
else {
nm[0] = 0;
nm[1] = 0;
}
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
} break;
memcpy(reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, nm, 16);
} break;
}
return r;
}
@ -284,7 +287,7 @@ 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()));
reinterpret_cast<struct sockaddr_in*>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
return r;
}
return InetAddress();
@ -293,34 +296,34 @@ InetAddress InetAddress::broadcast() const
InetAddress InetAddress::network() const
{
InetAddress r(*this);
switch(r.ss_family) {
switch (r.ss_family) {
case AF_INET:
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
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);
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;
memcpy(reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, nm, 16);
} break;
}
return r;
}
bool InetAddress::isEqualPrefix(const InetAddress &addr) const
bool InetAddress::isEqualPrefix(const InetAddress& addr) const
{
if (addr.ss_family == ss_family) {
switch(ss_family) {
switch (ss_family) {
case AF_INET6: {
const InetAddress mask(netmask());
InetAddress addr_mask(addr.netmask());
const uint8_t *n = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&addr_mask)->sin6_addr.s6_addr);
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) {
const uint8_t* n = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&addr_mask)->sin6_addr.s6_addr);
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] & n[i])) {
return false;
}
@ -332,23 +335,24 @@ bool InetAddress::isEqualPrefix(const InetAddress &addr) const
return false;
}
bool InetAddress::containsAddress(const InetAddress &addr) const
bool InetAddress::containsAddress(const InetAddress& addr) const
{
if (addr.ss_family == ss_family) {
switch(ss_family) {
switch (ss_family) {
case AF_INET: {
const unsigned int bits = netmaskBits();
if (bits == 0) {
return true;
}
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)) );
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) {
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;
}
@ -362,7 +366,7 @@ bool InetAddress::containsAddress(const InetAddress &addr) const
bool InetAddress::isNetwork() const
{
switch(ss_family) {
switch (ss_family) {
case AF_INET: {
unsigned int bits = netmaskBits();
if (bits <= 0) {
@ -371,7 +375,7 @@ bool InetAddress::isNetwork() const
if (bits >= 32) {
return false;
}
uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
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: {
@ -382,7 +386,7 @@ bool InetAddress::isNetwork() const
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);
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;
@ -398,55 +402,60 @@ bool InetAddress::isNetwork() const
return false;
}
bool InetAddress::operator==(const InetAddress &a) const
bool InetAddress::operator==(const InetAddress& a) const
{
if (ss_family == a.ss_family) {
switch(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));
(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));
(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 (memcmp(this, &a, sizeof(InetAddress)) == 0);
}
}
return false;
}
bool InetAddress::operator<(const InetAddress &a) const
bool InetAddress::operator<(const InetAddress& a) const
{
if (ss_family < a.ss_family) {
return true;
} else if (ss_family == a.ss_family) {
switch(ss_family) {
}
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) {
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) {
}
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) {
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) {
}
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) {
}
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) {
}
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;
}
}
@ -454,13 +463,13 @@ bool InetAddress::operator<(const InetAddress &a) const
}
break;
default:
return (memcmp(this,&a,sizeof(InetAddress)) < 0);
return (memcmp(this, &a, sizeof(InetAddress)) < 0);
}
}
return false;
}
InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
InetAddress InetAddress::makeIpv6LinkLocal(const MAC& mac)
{
struct sockaddr_in6 sin6;
sin6.sin6_family = AF_INET6;
@ -484,10 +493,10 @@ InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
return InetAddress(sin6);
}
InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress)
{
InetAddress r;
struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&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);
@ -505,15 +514,15 @@ InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
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
sin6->sin6_port = Utils::hton((uint16_t)88); // /88 includes 0xfd + network ID, discriminating by device ID below that
return r;
}
InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress)
InetAddress InetAddress::makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress)
{
nwid ^= (nwid >> 32);
InetAddress r;
struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
struct sockaddr_in6* const sin6 = reinterpret_cast<struct sockaddr_in6*>(&r);
sin6->sin6_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfc;
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24);
@ -530,4 +539,4 @@ InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress)
return r;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,15 +14,15 @@
#ifndef ZT_INETADDRESS_HPP
#define ZT_INETADDRESS_HPP
#include "../include/ZeroTierOne.h"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "MAC.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Utils.hpp"
#include "MAC.hpp"
#include "Buffer.hpp"
namespace ZeroTier {
@ -39,8 +39,7 @@ namespace ZeroTier {
* 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
{
struct InetAddress : public sockaddr_storage {
/**
* Loopback IPv4 address (no port)
*/
@ -58,134 +57,177 @@ struct InetAddress : public sockaddr_storage
* 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, // currently unused, formerly used for carrier-grade NAT ranges
IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc.
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, // currently unused, formerly used for carrier-grade NAT ranges
IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc.
};
// Can be used with the unordered maps and sets in c++11. We don't use C++11 in the core
// but this is safe to put here.
struct Hasher
{
inline std::size_t operator()(const InetAddress &a) const { return (std::size_t)a.hashCode(); }
struct Hasher {
inline std::size_t operator()(const InetAddress& a) const
{
return (std::size_t)a.hashCode();
}
};
InetAddress() { memset(this,0,sizeof(InetAddress)); }
InetAddress(const InetAddress &a) { memcpy(this,&a,sizeof(InetAddress)); }
InetAddress(const InetAddress *a) { memcpy(this,a,sizeof(InetAddress)); }
InetAddress(const struct sockaddr_storage &ss) { *this = ss; }
InetAddress(const struct sockaddr_storage *ss) { *this = ss; }
InetAddress(const struct sockaddr &sa) { *this = sa; }
InetAddress(const struct sockaddr *sa) { *this = sa; }
InetAddress(const struct sockaddr_in &sa) { *this = sa; }
InetAddress(const struct sockaddr_in *sa) { *this = sa; }
InetAddress(const struct sockaddr_in6 &sa) { *this = sa; }
InetAddress(const struct sockaddr_in6 *sa) { *this = sa; }
InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) { this->set(ipBytes,ipLen,port); }
InetAddress(const uint32_t ipv4,unsigned int port) { this->set(&ipv4,4,port); }
InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); }
InetAddress()
{
memset(this, 0, sizeof(InetAddress));
}
InetAddress(const InetAddress& a)
{
memcpy(this, &a, sizeof(InetAddress));
}
InetAddress(const InetAddress* a)
{
memcpy(this, a, sizeof(InetAddress));
}
InetAddress(const struct sockaddr_storage& ss)
{
*this = ss;
}
InetAddress(const struct sockaddr_storage* ss)
{
*this = ss;
}
InetAddress(const struct sockaddr& sa)
{
*this = sa;
}
InetAddress(const struct sockaddr* sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in& sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in* sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in6& sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in6* sa)
{
*this = sa;
}
InetAddress(const void* ipBytes, unsigned int ipLen, unsigned int port)
{
this->set(ipBytes, ipLen, port);
}
InetAddress(const uint32_t ipv4, unsigned int port)
{
this->set(&ipv4, 4, port);
}
InetAddress(const char* ipSlashPort)
{
this->fromString(ipSlashPort);
}
inline InetAddress &operator=(const InetAddress &a)
inline InetAddress& operator=(const InetAddress& a)
{
if (&a != this) {
memcpy(this,&a,sizeof(InetAddress));
memcpy(this, &a, sizeof(InetAddress));
}
return *this;
}
inline InetAddress &operator=(const InetAddress *a)
inline InetAddress& operator=(const InetAddress* a)
{
if (a != this) {
memcpy(this,a,sizeof(InetAddress));
memcpy(this, a, sizeof(InetAddress));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr_storage &ss)
inline InetAddress& operator=(const struct sockaddr_storage& ss)
{
if (reinterpret_cast<const InetAddress *>(&ss) != this) {
memcpy(this,&ss,sizeof(InetAddress));
if (reinterpret_cast<const InetAddress*>(&ss) != this) {
memcpy(this, &ss, sizeof(InetAddress));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr_storage *ss)
inline InetAddress& operator=(const struct sockaddr_storage* ss)
{
if (reinterpret_cast<const InetAddress *>(ss) != this) {
memcpy(this,ss,sizeof(InetAddress));
if (reinterpret_cast<const InetAddress*>(ss) != this) {
memcpy(this, ss, sizeof(InetAddress));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr_in &sa)
inline InetAddress& operator=(const struct sockaddr_in& sa)
{
if (reinterpret_cast<const InetAddress *>(&sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in));
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)
inline InetAddress& operator=(const struct sockaddr_in* sa)
{
if (reinterpret_cast<const InetAddress *>(sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,sa,sizeof(struct sockaddr_in));
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)
inline InetAddress& operator=(const struct sockaddr_in6& sa)
{
if (reinterpret_cast<const InetAddress *>(&sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in6));
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)
inline InetAddress& operator=(const struct sockaddr_in6* sa)
{
if (reinterpret_cast<const InetAddress *>(sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,sa,sizeof(struct sockaddr_in6));
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)
inline InetAddress& operator=(const struct sockaddr& sa)
{
if (reinterpret_cast<const InetAddress *>(&sa) != this) {
memset(this,0,sizeof(InetAddress));
switch(sa.sa_family) {
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));
memcpy(this, &sa, sizeof(struct sockaddr_in));
break;
case AF_INET6:
memcpy(this,&sa,sizeof(struct sockaddr_in6));
memcpy(this, &sa, sizeof(struct sockaddr_in6));
break;
}
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr *sa)
inline InetAddress& operator=(const struct sockaddr* sa)
{
if (reinterpret_cast<const InetAddress *>(sa) != this) {
memset(this,0,sizeof(InetAddress));
switch(sa->sa_family) {
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));
memcpy(this, sa, sizeof(struct sockaddr_in));
break;
case AF_INET6:
memcpy(this,sa,sizeof(struct sockaddr_in6));
memcpy(this, sa, sizeof(struct sockaddr_in6));
break;
}
}
@ -204,7 +246,7 @@ struct InetAddress : public sockaddr_storage
* @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);
void set(const void* ipBytes, unsigned int ipLen, unsigned int port);
/**
* Set the port component
@ -213,12 +255,12 @@ struct InetAddress : public sockaddr_storage
*/
inline void setPort(unsigned int port)
{
switch(ss_family) {
switch (ss_family) {
case AF_INET:
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
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);
reinterpret_cast<struct sockaddr_in6*>(this)->sin6_port = Utils::hton((uint16_t)port);
break;
}
}
@ -228,17 +270,17 @@ struct InetAddress : public sockaddr_storage
*/
inline bool isDefaultRoute() const
{
switch(ss_family) {
switch (ss_family) {
case AF_INET:
return ( (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == 0) && (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port == 0) );
return ((reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr == 0) && (reinterpret_cast<const struct sockaddr_in*>(this)->sin_port == 0));
case AF_INET6:
const uint8_t *ipb = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
for(int i=0;i<16;++i) {
const uint8_t* ipb = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
for (int i = 0; i < 16; ++i) {
if (ipb[i]) {
return false;
}
}
return (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port == 0);
return (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port == 0);
}
return false;
}
@ -246,29 +288,29 @@ struct InetAddress : public sockaddr_storage
/**
* @return ASCII IP/port format representation
*/
char *toString(char buf[64]) const;
char* toString(char buf[64]) const;
/**
* @return IP portion only, in ASCII string format
*/
char *toIpString(char buf[64]) const;
char* toIpString(char buf[64]) const;
/**
* @param ipSlashPort IP/port (port is optional, will be 0 if not included)
* @return True if address appeared to be valid
*/
bool fromString(const char *ipSlashPort);
bool fromString(const char* ipSlashPort);
/**
* @return Port or 0 if no port component defined
*/
inline unsigned int port() const
{
switch(ss_family) {
switch (ss_family) {
case AF_INET:
return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port));
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));
return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port));
default:
return 0;
}
@ -283,7 +325,10 @@ struct InetAddress : public sockaddr_storage
*
* @return Netmask bits
*/
inline unsigned int netmaskBits() const { return port(); }
inline unsigned int netmaskBits() const
{
return port();
}
/**
* @return True if netmask bits is valid for the address type
@ -291,7 +336,7 @@ struct InetAddress : public sockaddr_storage
inline bool netmaskBitsValid() const
{
const unsigned int n = port();
switch(ss_family) {
switch (ss_family) {
case AF_INET:
return (n <= 32);
case AF_INET6:
@ -308,7 +353,10 @@ struct InetAddress : public sockaddr_storage
*
* @return Gateway metric
*/
inline unsigned int metric() const { return port(); }
inline unsigned int metric() const
{
return port();
}
/**
* Construct a full netmask as an InetAddress
@ -340,7 +388,7 @@ struct InetAddress : public sockaddr_storage
* @param addr Address to check
* @return True if this IPv6 prefix matches the prefix of a given IPv6 address
*/
bool isEqualPrefix(const InetAddress &addr) const;
bool isEqualPrefix(const InetAddress& addr) const;
/**
* Test whether this IP/netmask contains this address
@ -348,28 +396,34 @@ struct InetAddress : public sockaddr_storage
* @param addr Address to check
* @return True if this IP/netmask (route) contains this address
*/
bool containsAddress(const InetAddress &addr) const;
bool containsAddress(const InetAddress& addr) const;
/**
* @return True if this is an IPv4 address
*/
inline bool isV4() const { return (ss_family == AF_INET); }
inline bool isV4() const
{
return (ss_family == AF_INET);
}
/**
* @return True if this is an IPv6 address
*/
inline bool isV6() const { return (ss_family == AF_INET6); }
inline bool isV6() const
{
return (ss_family == AF_INET6);
}
/**
* @return pointer to raw address bytes or NULL if not available
*/
inline const void *rawIpData() const
inline const void* rawIpData() const
{
switch(ss_family) {
switch (ss_family) {
case AF_INET:
return (const void *)&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
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);
return (const void*)(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
default:
return 0;
}
@ -381,14 +435,14 @@ struct InetAddress : public sockaddr_storage
inline InetAddress ipOnly() const
{
InetAddress r;
switch(ss_family) {
switch (ss_family) {
case AF_INET:
r.ss_family = AF_INET;
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr;
reinterpret_cast<struct sockaddr_in*>(&r)->sin_addr.s_addr = reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr;
break;
case AF_INET6:
r.ss_family = AF_INET6;
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
memcpy(reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, 16);
break;
}
return r;
@ -400,16 +454,16 @@ struct InetAddress : public sockaddr_storage
* @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
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);
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(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 (memcmp(this, &a, sizeof(InetAddress)) == 0);
}
return false;
}
@ -422,16 +476,16 @@ struct InetAddress : public sockaddr_storage
* @param a InetAddress to compare again
* @return True if only IP portions are equal (false for non-IP or null addresses)
*/
inline bool ipsEqual2(const InetAddress &a) const
inline bool ipsEqual2(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);
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, 8) == 0);
return (memcmp(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_addr.s6_addr, 8) == 0);
}
return (memcmp(this,&a,sizeof(InetAddress)) == 0);
return (memcmp(this, &a, sizeof(InetAddress)) == 0);
}
return false;
}
@ -439,19 +493,21 @@ struct InetAddress : public sockaddr_storage
inline unsigned long hashCode() const
{
if (ss_family == AF_INET) {
return ((unsigned long)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr + (unsigned long)reinterpret_cast<const struct sockaddr_in *>(this)->sin_port);
} else if (ss_family == AF_INET6) {
unsigned long tmp = reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port;
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
for(long i=0;i<16;++i) {
reinterpret_cast<uint8_t *>(&tmp)[i % sizeof(tmp)] ^= a[i];
return ((unsigned long)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr + (unsigned long)reinterpret_cast<const struct sockaddr_in*>(this)->sin_port);
}
else if (ss_family == AF_INET6) {
unsigned long tmp = reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port;
const uint8_t* a = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
for (long i = 0; i < 16; ++i) {
reinterpret_cast<uint8_t*>(&tmp)[i % sizeof(tmp)] ^= a[i];
}
return tmp;
} else {
unsigned long tmp = reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port;
const uint8_t *a = reinterpret_cast<const uint8_t *>(this);
for(long i=0;i<(long)sizeof(InetAddress);++i) {
reinterpret_cast<uint8_t *>(&tmp)[i % sizeof(tmp)] ^= a[i];
}
else {
unsigned long tmp = reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port;
const uint8_t* a = reinterpret_cast<const uint8_t*>(this);
for (long i = 0; i < (long)sizeof(InetAddress); ++i) {
reinterpret_cast<uint8_t*>(&tmp)[i % sizeof(tmp)] ^= a[i];
}
return tmp;
}
@ -460,7 +516,10 @@ struct InetAddress : public sockaddr_storage
/**
* Set to null/zero
*/
inline void zero() { memset(this,0,sizeof(InetAddress)); }
inline void zero()
{
memset(this, 0, sizeof(InetAddress));
}
/**
* Check whether this is a network/route rather than an IP assignment
@ -474,18 +533,18 @@ struct InetAddress : public sockaddr_storage
/**
* Find the total number of prefix bits that match between this IP and another
*
*
* @param b Second IP to compare with
* @return Number of matching prefix bits or 0 if none match or IPs are of different families (e.g. v4 and v6)
*/
inline unsigned int matchingPrefixBits(const InetAddress &b) const
inline unsigned int matchingPrefixBits(const InetAddress& b) const
{
unsigned int c = 0;
if (ss_family == b.ss_family) {
switch(ss_family) {
switch (ss_family) {
case AF_INET: {
uint32_t ip0 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
uint32_t ip1 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(&b)->sin_addr.s_addr);
uint32_t ip0 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr);
uint32_t ip1 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(&b)->sin_addr.s_addr);
while ((ip0 >> 31) == (ip1 >> 31)) {
ip0 <<= 1;
ip1 <<= 1;
@ -493,14 +552,15 @@ struct InetAddress : public sockaddr_storage
break;
}
}
} break;
} break;
case AF_INET6: {
const uint8_t *ip0 = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
const uint8_t *ip1 = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&b)->sin6_addr.s6_addr);
for(unsigned int i=0;i<16;++i) {
const uint8_t* ip0 = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
const uint8_t* ip1 = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&b)->sin6_addr.s6_addr);
for (unsigned int i = 0; i < 16; ++i) {
if (ip0[i] == ip1[i]) {
c += 8;
} else {
}
else {
uint8_t ip0b = ip0[i];
uint8_t ip1b = ip1[i];
uint8_t bit = 0x80;
@ -514,7 +574,7 @@ struct InetAddress : public sockaddr_storage
break;
}
}
} break;
} break;
}
}
return c;
@ -526,13 +586,13 @@ struct InetAddress : public sockaddr_storage
inline unsigned long rateGateHash() const
{
unsigned long h = 0;
switch(ss_family) {
switch (ss_family) {
case AF_INET:
h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) & 0xffffff00) >> 8;
h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr) & 0xffffff00) >> 8;
h ^= (h >> 14);
break;
case AF_INET6: {
const uint8_t *ip = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
const uint8_t* ip = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
h = ((unsigned long)ip[0]);
h <<= 1;
h += ((unsigned long)ip[1]);
@ -544,7 +604,7 @@ struct InetAddress : public sockaddr_storage
h += ((unsigned long)ip[4]);
h <<= 1;
h += ((unsigned long)ip[5]);
} break;
} break;
}
return (h & 0x3fff);
}
@ -552,23 +612,25 @@ struct InetAddress : public sockaddr_storage
/**
* @return True if address family is non-zero
*/
inline operator bool() const { return (ss_family != 0); }
inline operator bool() const
{
return (ss_family != 0);
}
template<unsigned int C>
inline void serialize(Buffer<C> &b) const
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) {
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
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
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);
@ -576,12 +638,11 @@ struct InetAddress : public sockaddr_storage
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
memset(this,0,sizeof(InetAddress));
memset(this, 0, sizeof(InetAddress));
unsigned int p = startAt;
switch(b[p++]) {
switch (b[p++]) {
case 0:
return 1;
case 0x01:
@ -593,19 +654,19 @@ struct InetAddress : public sockaddr_storage
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
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);
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));
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);
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));
reinterpret_cast<struct sockaddr_in*>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p));
p += 2;
break;
default:
@ -614,18 +675,30 @@ struct InetAddress : public sockaddr_storage
return (p - startAt);
}
bool operator==(const InetAddress &a) const;
bool operator<(const InetAddress &a) const;
inline bool operator!=(const InetAddress &a) const { return !(*this == a); }
inline bool operator>(const InetAddress &a) const { return (a < *this); }
inline bool operator<=(const InetAddress &a) const { return !(a < *this); }
inline bool operator>=(const InetAddress &a) const { return !(*this < a); }
bool operator==(const InetAddress& a) const;
bool operator<(const InetAddress& a) const;
inline bool operator!=(const InetAddress& a) const
{
return ! (*this == a);
}
inline bool operator>(const InetAddress& a) const
{
return (a < *this);
}
inline bool operator<=(const InetAddress& a) const
{
return ! (a < *this);
}
inline bool operator>=(const InetAddress& a) const
{
return ! (*this < a);
}
/**
* @param mac MAC address seed
* @return IPv6 link-local address
*/
static InetAddress makeIpv6LinkLocal(const MAC &mac);
static InetAddress makeIpv6LinkLocal(const MAC& mac);
/**
* Compute private IPv6 unicast address from network ID and ZeroTier address
@ -668,14 +741,14 @@ struct InetAddress : public sockaddr_storage
* @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);
static InetAddress makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress);
/**
* Compute a private IPv6 "6plane" unicast address from network ID and ZeroTier address
*/
static InetAddress makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress);
static InetAddress makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress);
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -14,64 +14,81 @@
#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"
#include "Constants.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
namespace ZeroTier {
/**
* 48-byte Ethernet MAC address
*/
class MAC
{
public:
MAC() : _m(0ULL) {}
MAC(const MAC &m) : _m(m._m) {}
class MAC {
public:
MAC() : _m(0ULL)
{
}
MAC(const MAC& m) : _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) :
_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 void *bits,unsigned int len) { setTo(bits,len); }
MAC(const Address &ztaddr,uint64_t nwid) { fromAddress(ztaddr,nwid); }
MAC(const uint64_t m) : _m(m & 0xffffffffffffULL) {}
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)
: _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 void* bits, unsigned int len)
{
setTo(bits, len);
}
MAC(const Address& ztaddr, uint64_t nwid)
{
fromAddress(ztaddr, nwid);
}
MAC(const uint64_t m) : _m(m & 0xffffffffffffULL)
{
}
/**
* @return MAC in 64-bit integer
*/
inline uint64_t toInt() const { return _m; }
inline uint64_t toInt() const
{
return _m;
}
/**
* Set MAC to zero
*/
inline void zero() { _m = 0ULL; }
inline void zero()
{
_m = 0ULL;
}
/**
* @return True if MAC is non-zero
*/
inline operator bool() const { return (_m != 0ULL); }
inline operator bool() const
{
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)
inline void setTo(const void* bits, unsigned int len)
{
if (len < 6) {
_m = 0ULL;
return;
}
const unsigned char *b = (const unsigned char *)bits;
_m = ((((uint64_t)*b) & 0xff) << 40);
const unsigned char* b = (const unsigned char*)bits;
_m = ((((uint64_t)*b) & 0xff) << 40);
++b;
_m |= ((((uint64_t)*b) & 0xff) << 32);
++b;
@ -88,12 +105,12 @@ public:
* @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
inline void copyTo(void* buf, unsigned int len) const
{
if (len < 6) {
return;
}
unsigned char *b = (unsigned char *)buf;
unsigned char* b = (unsigned char*)buf;
*(b++) = (unsigned char)((_m >> 40) & 0xff);
*(b++) = (unsigned char)((_m >> 32) & 0xff);
*(b++) = (unsigned char)((_m >> 24) & 0xff);
@ -107,10 +124,9 @@ public:
*
* @param b Buffer to append to
*/
template<unsigned int C>
inline void appendTo(Buffer<C> &b) const
template <unsigned int C> inline void appendTo(Buffer<C>& b) const
{
unsigned char *p = (unsigned char *)b.appendField(6);
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);
@ -122,17 +138,26 @@ public:
/**
* @return True if this is broadcast (all 0xff)
*/
inline bool isBroadcast() const { return (_m == 0xffffffffffffULL); }
inline bool isBroadcast() const
{
return (_m == 0xffffffffffffULL);
}
/**
* @return True if this is a multicast MAC
*/
inline bool isMulticast() const { return ((_m & 0x010000000000ULL) != 0ULL); }
inline bool isMulticast() const
{
return ((_m & 0x010000000000ULL) != 0ULL);
}
/**
* @param True if this is a locally-administered MAC
*/
inline bool isLocallyAdministered() const { return ((_m & 0x020000000000ULL) != 0ULL); }
inline bool isLocallyAdministered() const
{
return ((_m & 0x020000000000ULL) != 0ULL);
}
/**
* Set this MAC to a MAC derived from an address and a network ID
@ -140,10 +165,10 @@ public:
* @param ztaddr ZeroTier address
* @param nwid 64-bit network ID
*/
inline void fromAddress(const Address &ztaddr,uint64_t nwid)
inline void fromAddress(const Address& ztaddr, uint64_t nwid)
{
uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40;
m |= ztaddr.toInt(); // a is 40 bits
m |= ztaddr.toInt(); // a is 40 bits
m ^= ((nwid >> 8) & 0xff) << 32;
m ^= ((nwid >> 16) & 0xff) << 24;
m ^= ((nwid >> 24) & 0xff) << 16;
@ -161,8 +186,8 @@ public:
*/
inline Address toAddress(uint64_t nwid) const
{
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
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;
@ -176,24 +201,33 @@ public:
*/
static inline unsigned char firstOctetForNetwork(uint64_t nwid)
{
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
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 { return (unsigned char)((_m >> (40 - (i * 8))) & 0xff); }
inline unsigned char operator[](unsigned int i) const
{
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 { return 6; }
inline unsigned int size() const
{
return 6;
}
inline unsigned long hashCode() const { return (unsigned long)_m; }
inline unsigned long hashCode() const
{
return (unsigned long)_m;
}
inline char *toString(char buf[18]) const
inline char* toString(char buf[18]) const
{
buf[0] = Utils::HEXCHARS[(_m >> 44) & 0xf];
buf[1] = Utils::HEXCHARS[(_m >> 40) & 0xf];
@ -216,28 +250,46 @@ public:
return buf;
}
inline MAC &operator=(const MAC &m)
inline MAC& operator=(const MAC& m)
{
_m = m._m;
return *this;
}
inline MAC &operator=(const uint64_t m)
inline MAC& operator=(const uint64_t m)
{
_m = m;
return *this;
}
inline bool operator==(const MAC &m) const { return (_m == m._m); }
inline bool operator!=(const MAC &m) const { return (_m != m._m); }
inline bool operator<(const MAC &m) const { return (_m < m._m); }
inline bool operator<=(const MAC &m) const { return (_m <= m._m); }
inline bool operator>(const MAC &m) const { return (_m > m._m); }
inline bool operator>=(const MAC &m) const { return (_m >= m._m); }
inline bool operator==(const MAC& m) const
{
return (_m == m._m);
}
inline bool operator!=(const MAC& m) const
{
return (_m != m._m);
}
inline bool operator<(const MAC& m) const
{
return (_m < m._m);
}
inline bool operator<=(const MAC& m) const
{
return (_m <= m._m);
}
inline bool operator>(const MAC& m) const
{
return (_m > m._m);
}
inline bool operator>=(const MAC& m) const
{
return (_m >= m._m);
}
private:
private:
uint64_t _m;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,47 +11,41 @@
*/
/****/
#include <algorithm>
#include "Membership.hpp"
#include "RuntimeEnvironment.hpp"
#include "Peer.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Packet.hpp"
#include "Node.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
#include "Trace.hpp"
#include <algorithm>
namespace ZeroTier {
Membership::Membership() :
_lastUpdatedMulticast(0),
_comRevocationThreshold(0),
_lastPushedCredentials(0),
_revocations(4),
_remoteTags(4),
_remoteCaps(4),
_remoteCoos(4)
Membership::Membership() : _lastUpdatedMulticast(0), _comRevocationThreshold(0), _lastPushedCredentials(0), _revocations(4), _remoteTags(4), _remoteCaps(4), _remoteCoos(4)
{
}
void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf)
void Membership::pushCredentials(const RuntimeEnvironment* RR, void* tPtr, const int64_t now, const Address& peerAddress, const NetworkConfig& nconf)
{
const Capability *sendCaps[ZT_MAX_NETWORK_CAPABILITIES];
const Capability* sendCaps[ZT_MAX_NETWORK_CAPABILITIES];
unsigned int sendCapCount = 0;
for(unsigned int c=0;c<nconf.capabilityCount;++c) {
for (unsigned int c = 0; c < nconf.capabilityCount; ++c) {
sendCaps[sendCapCount++] = &(nconf.capabilities[c]);
}
const Tag *sendTags[ZT_MAX_NETWORK_TAGS];
const Tag* sendTags[ZT_MAX_NETWORK_TAGS];
unsigned int sendTagCount = 0;
for(unsigned int t=0;t<nconf.tagCount;++t) {
for (unsigned int t = 0; t < nconf.tagCount; ++t) {
sendTags[sendTagCount++] = &(nconf.tags[t]);
}
const CertificateOfOwnership *sendCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
const CertificateOfOwnership* sendCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
unsigned int sendCooCount = 0;
for(unsigned int c=0;c<nconf.certificateOfOwnershipCount;++c) {
for (unsigned int c = 0; c < nconf.certificateOfOwnershipCount; ++c) {
sendCoos[sendCooCount++] = &(nconf.certificatesOfOwnership[c]);
}
@ -59,8 +53,8 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
unsigned int tagPtr = 0;
unsigned int cooPtr = 0;
bool sendCom = (bool)(nconf.com);
while ((capPtr < sendCapCount)||(tagPtr < sendTagCount)||(cooPtr < sendCooCount)||(sendCom)) {
Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
while ((capPtr < sendCapCount) || (tagPtr < sendTagCount) || (cooPtr < sendCooCount) || (sendCom)) {
Packet outp(peerAddress, RR->identity.address(), Packet::VERB_NETWORK_CREDENTIALS);
if (sendCom) {
sendCom = false;
@ -71,20 +65,20 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
const unsigned int capCountAt = outp.size();
outp.addSize(2);
unsigned int thisPacketCapCount = 0;
while ((capPtr < sendCapCount)&&((outp.size() + sizeof(Capability) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
while ((capPtr < sendCapCount) && ((outp.size() + sizeof(Capability) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
sendCaps[capPtr++]->serialize(outp);
++thisPacketCapCount;
}
outp.setAt(capCountAt,(uint16_t)thisPacketCapCount);
outp.setAt(capCountAt, (uint16_t)thisPacketCapCount);
const unsigned int tagCountAt = outp.size();
outp.addSize(2);
unsigned int thisPacketTagCount = 0;
while ((tagPtr < sendTagCount)&&((outp.size() + sizeof(Tag) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
while ((tagPtr < sendTagCount) && ((outp.size() + sizeof(Tag) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
sendTags[tagPtr++]->serialize(outp);
++thisPacketTagCount;
}
outp.setAt(tagCountAt,(uint16_t)thisPacketTagCount);
outp.setAt(tagCountAt, (uint16_t)thisPacketTagCount);
// No revocations, these propagate differently
outp.append((uint16_t)0);
@ -92,43 +86,43 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
const unsigned int cooCountAt = outp.size();
outp.addSize(2);
unsigned int thisPacketCooCount = 0;
while ((cooPtr < sendCooCount)&&((outp.size() + sizeof(CertificateOfOwnership) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
while ((cooPtr < sendCooCount) && ((outp.size() + sizeof(CertificateOfOwnership) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
sendCoos[cooPtr++]->serialize(outp);
++thisPacketCooCount;
}
outp.setAt(cooCountAt,(uint16_t)thisPacketCooCount);
outp.setAt(cooCountAt, (uint16_t)thisPacketCooCount);
outp.compress();
RR->sw->send(tPtr,outp,true);
RR->sw->send(tPtr, outp, true);
Metrics::pkt_network_credentials_out++;
}
_lastPushedCredentials = now;
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com)
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfMembership& com)
{
const int64_t newts = com.timestamp();
if (newts <= _comRevocationThreshold) {
RR->t->credentialRejected(tPtr,com,"revoked");
RR->t->credentialRejected(tPtr, com, "revoked");
return ADD_REJECTED;
}
const int64_t oldts = _com.timestamp();
if (newts < oldts) {
RR->t->credentialRejected(tPtr,com,"old");
RR->t->credentialRejected(tPtr, com, "old");
return ADD_REJECTED;
}
if (_com == com) {
return ADD_ACCEPTED_REDUNDANT;
}
switch(com.verify(RR,tPtr)) {
switch (com.verify(RR, tPtr)) {
default:
RR->t->credentialRejected(tPtr,com,"invalid");
RR->t->credentialRejected(tPtr, com, "invalid");
return ADD_REJECTED;
case 0:
//printf("%.16llx %.10llx replacing COM %lld with %lld\n", com.networkId(), com.issuedTo().toInt(), _com.timestamp(), com.timestamp()); fflush(stdout);
// printf("%.16llx %.10llx replacing COM %lld with %lld\n", com.networkId(), com.issuedTo().toInt(), _com.timestamp(), com.timestamp()); fflush(stdout);
_com = com;
return ADD_ACCEPTED_NEW;
case 1:
@ -137,13 +131,13 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
}
// Template out addCredential() for many cred types to avoid copypasta
template<typename C>
static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remoteCreds,const Hashtable<uint64_t,int64_t> &revocations,const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const C &cred)
template <typename C>
static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t, C>& remoteCreds, const Hashtable<uint64_t, int64_t>& revocations, const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const C& cred)
{
C *rc = remoteCreds.get(cred.id());
C* rc = remoteCreds.get(cred.id());
if (rc) {
if (rc->timestamp() > cred.timestamp()) {
RR->t->credentialRejected(tPtr,cred,"old");
RR->t->credentialRejected(tPtr, cred, "old");
return Membership::ADD_REJECTED;
}
if (*rc == cred) {
@ -151,18 +145,18 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
}
}
const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id()));
if ((rt)&&(*rt >= cred.timestamp())) {
RR->t->credentialRejected(tPtr,cred,"revoked");
const int64_t* const rt = revocations.get(Membership::credentialKey(C::credentialType(), cred.id()));
if ((rt) && (*rt >= cred.timestamp())) {
RR->t->credentialRejected(tPtr, cred, "revoked");
return Membership::ADD_REJECTED;
}
switch(cred.verify(RR,tPtr)) {
switch (cred.verify(RR, tPtr)) {
default:
RR->t->credentialRejected(tPtr,cred,"invalid");
RR->t->credentialRejected(tPtr, cred, "invalid");
return Membership::ADD_REJECTED;
case 0:
if (!rc) {
if (! rc) {
rc = &(remoteCreds[cred.id()]);
}
*rc = cred;
@ -172,20 +166,29 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
}
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl<Tag>(_remoteTags,_revocations,RR,tPtr,nconf,tag); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl<Capability>(_remoteCaps,_revocations,RR,tPtr,nconf,cap); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl<CertificateOfOwnership>(_remoteCoos,_revocations,RR,tPtr,nconf,coo); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev)
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Tag& tag)
{
int64_t *rt;
switch(rev.verify(RR,tPtr)) {
return _addCredImpl<Tag>(_remoteTags, _revocations, RR, tPtr, nconf, tag);
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Capability& cap)
{
return _addCredImpl<Capability>(_remoteCaps, _revocations, RR, tPtr, nconf, cap);
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfOwnership& coo)
{
return _addCredImpl<CertificateOfOwnership>(_remoteCoos, _revocations, RR, tPtr, nconf, coo);
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Revocation& rev)
{
int64_t* rt;
switch (rev.verify(RR, tPtr)) {
default:
RR->t->credentialRejected(tPtr,rev,"invalid");
RR->t->credentialRejected(tPtr, rev, "invalid");
return ADD_REJECTED;
case 0: {
const Credential::Type ct = rev.type();
switch(ct) {
switch (ct) {
case Credential::CREDENTIAL_TYPE_COM:
if (rev.threshold() > _comRevocationThreshold) {
_comRevocationThreshold = rev.threshold();
@ -195,7 +198,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
case Credential::CREDENTIAL_TYPE_CAPABILITY:
case Credential::CREDENTIAL_TYPE_TAG:
case Credential::CREDENTIAL_TYPE_COO:
rt = &(_revocations[credentialKey(ct,rev.credentialId())]);
rt = &(_revocations[credentialKey(ct, rev.credentialId())]);
if (*rt < rev.threshold()) {
*rt = rev.threshold();
_comRevocationThreshold = rev.threshold();
@ -203,7 +206,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
}
return ADD_ACCEPTED_REDUNDANT;
default:
RR->t->credentialRejected(tPtr,rev,"invalid");
RR->t->credentialRejected(tPtr, rev, "invalid");
return ADD_REJECTED;
}
}
@ -212,11 +215,11 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
}
}
void Membership::clean(const int64_t now,const NetworkConfig &nconf)
void Membership::clean(const int64_t now, const NetworkConfig& nconf)
{
_cleanCredImpl<Tag>(nconf,_remoteTags);
_cleanCredImpl<Capability>(nconf,_remoteCaps);
_cleanCredImpl<CertificateOfOwnership>(nconf,_remoteCoos);
_cleanCredImpl<Tag>(nconf, _remoteTags);
_cleanCredImpl<Capability>(nconf, _remoteCaps);
_cleanCredImpl<CertificateOfOwnership>(nconf, _remoteCoos);
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,17 +14,17 @@
#ifndef ZT_MEMBERSHIP_HPP
#define ZT_MEMBERSHIP_HPP
#include <stdint.h>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Capability.hpp"
#include "CertificateOfMembership.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "Hashtable.hpp"
#include "CertificateOfMembership.hpp"
#include "Capability.hpp"
#include "Tag.hpp"
#include "Revocation.hpp"
#include "NetworkConfig.hpp"
#include "Revocation.hpp"
#include "Tag.hpp"
#include <stdint.h>
#define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL
@ -40,16 +40,9 @@ class Network;
*
* This class is not thread safe. It must be locked externally.
*/
class Membership
{
public:
enum AddCredentialResult
{
ADD_REJECTED,
ADD_ACCEPTED_NEW,
ADD_ACCEPTED_REDUNDANT,
ADD_DEFERRED_FOR_WHOIS
};
class Membership {
public:
enum AddCredentialResult { ADD_REJECTED, ADD_ACCEPTED_NEW, ADD_ACCEPTED_REDUNDANT, ADD_DEFERRED_FOR_WHOIS };
Membership();
@ -62,11 +55,20 @@ public:
* @param peerAddress Address of member peer (the one that this Membership describes)
* @param nconf My network config
*/
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf);
void pushCredentials(const RuntimeEnvironment* RR, void* tPtr, const int64_t now, const Address& peerAddress, const NetworkConfig& nconf);
inline int64_t lastPushedCredentials() { return _lastPushedCredentials; }
inline int64_t comTimestamp() { return _com.timestamp(); }
inline int64_t comRevocationThreshold() { return _comRevocationThreshold; }
inline int64_t lastPushedCredentials()
{
return _lastPushedCredentials;
}
inline int64_t comTimestamp()
{
return _com.timestamp();
}
inline int64_t comRevocationThreshold()
{
return _comRevocationThreshold;
}
/**
* Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true
@ -90,14 +92,14 @@ public:
* @param otherNodeIdentity Identity of remote node
* @return True if this peer is allowed on this network at all
*/
inline bool isAllowedOnNetwork(const NetworkConfig &thisNodeNetworkConfig, const Identity &otherNodeIdentity) const
inline bool isAllowedOnNetwork(const NetworkConfig& thisNodeNetworkConfig, const Identity& otherNodeIdentity) const
{
return thisNodeNetworkConfig.isPublic() || (((_com.timestamp() > _comRevocationThreshold) && (thisNodeNetworkConfig.com.agreesWith(_com, otherNodeIdentity))));
}
inline bool recentlyAssociated(const int64_t now) const
{
return ((_com)&&((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT));
return ((_com) && ((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT));
}
/**
@ -108,18 +110,17 @@ public:
* @param r Resource to check
* @return True if this peer has a certificate of ownership for the given resource
*/
template<typename T>
inline bool hasCertificateOfOwnershipFor(const NetworkConfig &nconf,const T &r) const
template <typename T> inline bool hasCertificateOfOwnershipFor(const NetworkConfig& nconf, const T& r) const
{
uint32_t *k = (uint32_t *)0;
CertificateOfOwnership *v = (CertificateOfOwnership *)0;
Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos)));
while (i.next(k,v)) {
if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r))) {
uint32_t* k = (uint32_t*)0;
CertificateOfOwnership* v = (CertificateOfOwnership*)0;
Hashtable<uint32_t, CertificateOfOwnership>::Iterator i(*(const_cast<Hashtable<uint32_t, CertificateOfOwnership>*>(&_remoteCoos)));
while (i.next(k, v)) {
if (_isCredentialTimestampValid(nconf, *v) && (v->owns(r))) {
return true;
}
}
return _isV6NDPEmulated(nconf,r);
return _isV6NDPEmulated(nconf, r);
}
/**
@ -129,36 +130,36 @@ public:
* @param id Tag ID
* @return Pointer to tag or NULL if not found
*/
inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
inline const Tag* getTag(const NetworkConfig& nconf, const uint32_t id) const
{
const Tag *const t = _remoteTags.get(id);
return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
const Tag* const t = _remoteTags.get(id);
return (((t) && (_isCredentialTimestampValid(nconf, *t))) ? t : (Tag*)0);
}
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com);
AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfMembership& com);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag);
AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Tag& tag);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap);
AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Capability& cap);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo);
AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfOwnership& coo);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev);
AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Revocation& rev);
/**
* Clean internal databases of stale entries
@ -166,24 +167,30 @@ public:
* @param now Current time
* @param nconf Current network configuration
*/
void clean(const int64_t now,const NetworkConfig &nconf);
void clean(const int64_t now, const NetworkConfig& nconf);
/**
* Generates a key for the internal use in indexing credentials by type and credential ID
*/
static uint64_t credentialKey(const Credential::Type &t,const uint32_t i) { return (((uint64_t)t << 32) | (uint64_t)i); }
private:
inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const MAC &m) const { return false; }
inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const InetAddress &ip) const
static uint64_t credentialKey(const Credential::Type& t, const uint32_t i)
{
if ((ip.isV6())&&(nconf.ndpEmulation())) {
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
return (((uint64_t)t << 32) | (uint64_t)i);
}
private:
inline bool _isV6NDPEmulated(const NetworkConfig& nconf, const MAC& m) const
{
return false;
}
inline bool _isV6NDPEmulated(const NetworkConfig& nconf, const InetAddress& ip) const
{
if ((ip.isV6()) && (nconf.ndpEmulation())) {
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId, nconf.issuedTo.toInt()));
for (unsigned int i = 0; i < nconf.staticIpCount; ++i) {
if (nconf.staticIps[i].ipsEqual(sixpl)) {
bool prefixMatches = true;
for(unsigned int j=0;j<5;++j) { // check for match on /40
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&sixpl)->sin6_addr.s6_addr)[j]) {
for (unsigned int j = 0; j < 5; ++j) { // check for match on /40
if ((((const struct sockaddr_in6*)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6*)&sixpl)->sin6_addr.s6_addr)[j]) {
prefixMatches = false;
break;
}
@ -195,12 +202,12 @@ private:
}
}
const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt()));
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId, nconf.issuedTo.toInt()));
for (unsigned int i = 0; i < nconf.staticIpCount; ++i) {
if (nconf.staticIps[i].ipsEqual(rfc4193)) {
bool prefixMatches = true;
for(unsigned int j=0;j<11;++j) { // check for match on /88
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&rfc4193)->sin6_addr.s6_addr)[j]) {
for (unsigned int j = 0; j < 11; ++j) { // check for match on /88
if ((((const struct sockaddr_in6*)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6*)&rfc4193)->sin6_addr.s6_addr)[j]) {
prefixMatches = false;
break;
}
@ -215,25 +222,23 @@ private:
return false;
}
template<typename C>
inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const
template <typename C> inline bool _isCredentialTimestampValid(const NetworkConfig& nconf, const C& remoteCredential) const
{
const int64_t ts = remoteCredential.timestamp();
if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) {
const int64_t *threshold = _revocations.get(credentialKey(C::credentialType(),remoteCredential.id()));
return ((!threshold)||(ts > *threshold));
const int64_t* threshold = _revocations.get(credentialKey(C::credentialType(), remoteCredential.id()));
return ((! threshold) || (ts > *threshold));
}
return false;
}
template<typename C>
inline void _cleanCredImpl(const NetworkConfig &nconf,Hashtable<uint32_t,C> &remoteCreds)
template <typename C> inline void _cleanCredImpl(const NetworkConfig& nconf, Hashtable<uint32_t, C>& remoteCreds)
{
uint32_t *k = (uint32_t *)0;
C *v = (C *)0;
typename Hashtable<uint32_t,C>::Iterator i(remoteCreds);
while (i.next(k,v)) {
if (!_isCredentialTimestampValid(nconf,*v)) {
uint32_t* k = (uint32_t*)0;
C* v = (C*)0;
typename Hashtable<uint32_t, C>::Iterator i(remoteCreds);
while (i.next(k, v)) {
if (! _isCredentialTimestampValid(nconf, *v)) {
remoteCreds.erase(*k);
}
}
@ -252,45 +257,39 @@ private:
CertificateOfMembership _com;
// Revocations by credentialKey()
Hashtable< uint64_t,int64_t > _revocations;
Hashtable<uint64_t, int64_t> _revocations;
// Remote credentials that we have received from this member (and that are valid)
Hashtable< uint32_t,Tag > _remoteTags;
Hashtable< uint32_t,Capability > _remoteCaps;
Hashtable< uint32_t,CertificateOfOwnership > _remoteCoos;
Hashtable<uint32_t, Tag> _remoteTags;
Hashtable<uint32_t, Capability> _remoteCaps;
Hashtable<uint32_t, CertificateOfOwnership> _remoteCoos;
public:
class CapabilityIterator
{
public:
CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
_hti(m._remoteCaps),
_k((uint32_t *)0),
_c((Capability *)0),
_m(m),
_nconf(nconf)
public:
class CapabilityIterator {
public:
CapabilityIterator(Membership& m, const NetworkConfig& nconf) : _hti(m._remoteCaps), _k((uint32_t*)0), _c((Capability*)0), _m(m), _nconf(nconf)
{
}
inline Capability *next()
inline Capability* next()
{
while (_hti.next(_k,_c)) {
if (_m._isCredentialTimestampValid(_nconf,*_c)) {
while (_hti.next(_k, _c)) {
if (_m._isCredentialTimestampValid(_nconf, *_c)) {
return _c;
}
}
return (Capability *)0;
return (Capability*)0;
}
private:
Hashtable< uint32_t,Capability >::Iterator _hti;
uint32_t *_k;
Capability *_c;
Membership &_m;
const NetworkConfig &_nconf;
private:
Hashtable<uint32_t, Capability>::Iterator _hti;
uint32_t* _k;
Capability* _c;
Membership& _m;
const NetworkConfig& _nconf;
};
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -10,263 +10,155 @@
* of this software will be governed by version 2.0 of the Apache License.
*/
#include <prometheus/simpleapi.h>
#include <prometheus/histogram.h>
#include <prometheus/simpleapi.h>
namespace prometheus {
namespace simpleapi {
std::shared_ptr<Registry> registry_ptr = std::make_shared<Registry>();
Registry& registry = *registry_ptr;
SaveToFile saver;
}
}
namespace simpleapi {
std::shared_ptr<Registry> registry_ptr = std::make_shared<Registry>();
Registry& registry = *registry_ptr;
SaveToFile saver;
} // namespace simpleapi
} // namespace prometheus
namespace ZeroTier {
namespace Metrics {
// Packet Type Counts
prometheus::simpleapi::counter_family_t packets
{ "zt_packet", "ZeroTier packet type counts"};
namespace Metrics {
// Packet Type Counts
prometheus::simpleapi::counter_family_t packets { "zt_packet", "ZeroTier packet type counts" };
// Incoming packets
prometheus::simpleapi::counter_metric_t pkt_nop_in
{ packets.Add({{"packet_type", "nop"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_in
{ packets.Add({{"packet_type", "error"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ack_in
{ packets.Add({{"packet_type", "ack"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_qos_in
{ packets.Add({{"packet_type", "qos"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_hello_in
{ packets.Add({{"packet_type", "hello"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ok_in
{ packets.Add({{"packet_type", "ok"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_whois_in
{ packets.Add({{"packet_type", "whois"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_rendezvous_in
{ packets.Add({{"packet_type", "rendezvous"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_frame_in
{ packets.Add({{"packet_type", "frame"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ext_frame_in
{ packets.Add({{"packet_type", "ext_frame"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_echo_in
{ packets.Add({{"packet_type", "echo"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_like_in
{ packets.Add({{"packet_type", "multicast_like"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_credentials_in
{ packets.Add({{"packet_type", "network_credentials"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_request_in
{ packets.Add({{"packet_type", "network_config_request"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_in
{ packets.Add({{"packet_type", "network_config"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in
{ packets.Add({{"packet_type", "multicast_gather"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in
{ packets.Add({{"packet_type", "multicast_frame"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in
{ packets.Add({{"packet_type", "push_direct_paths"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_user_message_in
{ packets.Add({{"packet_type", "user_message"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_remote_trace_in
{ packets.Add({{"packet_type", "remote_trace"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in
{ packets.Add({{"packet_type", "path_negotiation_request"}, {"direction", "rx"}}) };
// Incoming packets
prometheus::simpleapi::counter_metric_t pkt_nop_in { packets.Add({ { "packet_type", "nop" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_in { packets.Add({ { "packet_type", "error" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ack_in { packets.Add({ { "packet_type", "ack" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_qos_in { packets.Add({ { "packet_type", "qos" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_hello_in { packets.Add({ { "packet_type", "hello" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ok_in { packets.Add({ { "packet_type", "ok" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_whois_in { packets.Add({ { "packet_type", "whois" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_rendezvous_in { packets.Add({ { "packet_type", "rendezvous" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_frame_in { packets.Add({ { "packet_type", "frame" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ext_frame_in { packets.Add({ { "packet_type", "ext_frame" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_echo_in { packets.Add({ { "packet_type", "echo" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_multicast_like_in { packets.Add({ { "packet_type", "multicast_like" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_network_credentials_in { packets.Add({ { "packet_type", "network_credentials" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_network_config_request_in { packets.Add({ { "packet_type", "network_config_request" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_network_config_in { packets.Add({ { "packet_type", "network_config" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in { packets.Add({ { "packet_type", "multicast_gather" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in { packets.Add({ { "packet_type", "multicast_frame" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in { packets.Add({ { "packet_type", "push_direct_paths" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_user_message_in { packets.Add({ { "packet_type", "user_message" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_remote_trace_in { packets.Add({ { "packet_type", "remote_trace" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in { packets.Add({ { "packet_type", "path_negotiation_request" }, { "direction", "rx" } }) };
// Outgoing packets
prometheus::simpleapi::counter_metric_t pkt_nop_out
{ packets.Add({{"packet_type", "nop"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_out
{ packets.Add({{"packet_type", "error"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ack_out
{ packets.Add({{"packet_type", "ack"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_qos_out
{ packets.Add({{"packet_type", "qos"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_hello_out
{ packets.Add({{"packet_type", "hello"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ok_out
{ packets.Add({{"packet_type", "ok"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_whois_out
{ packets.Add({{"packet_type", "whois"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_rendezvous_out
{ packets.Add({{"packet_type", "rendezvous"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_frame_out
{ packets.Add({{"packet_type", "frame"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ext_frame_out
{ packets.Add({{"packet_type", "ext_frame"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_echo_out
{ packets.Add({{"packet_type", "echo"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_like_out
{ packets.Add({{"packet_type", "multicast_like"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_credentials_out
{ packets.Add({{"packet_type", "network_credentials"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_request_out
{ packets.Add({{"packet_type", "network_config_request"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_out
{ packets.Add({{"packet_type", "network_config"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out
{ packets.Add({{"packet_type", "multicast_gather"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out
{ packets.Add({{"packet_type", "multicast_frame"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out
{ packets.Add({{"packet_type", "push_direct_paths"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_user_message_out
{ packets.Add({{"packet_type", "user_message"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_remote_trace_out
{ packets.Add({{"packet_type", "remote_trace"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out
{ packets.Add({{"packet_type", "path_negotiation_request"}, {"direction", "tx"}}) };
// Outgoing packets
prometheus::simpleapi::counter_metric_t pkt_nop_out { packets.Add({ { "packet_type", "nop" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_out { packets.Add({ { "packet_type", "error" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ack_out { packets.Add({ { "packet_type", "ack" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_qos_out { packets.Add({ { "packet_type", "qos" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_hello_out { packets.Add({ { "packet_type", "hello" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ok_out { packets.Add({ { "packet_type", "ok" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_whois_out { packets.Add({ { "packet_type", "whois" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_rendezvous_out { packets.Add({ { "packet_type", "rendezvous" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_frame_out { packets.Add({ { "packet_type", "frame" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ext_frame_out { packets.Add({ { "packet_type", "ext_frame" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_echo_out { packets.Add({ { "packet_type", "echo" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_multicast_like_out { packets.Add({ { "packet_type", "multicast_like" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_network_credentials_out { packets.Add({ { "packet_type", "network_credentials" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_network_config_request_out { packets.Add({ { "packet_type", "network_config_request" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_network_config_out { packets.Add({ { "packet_type", "network_config" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out { packets.Add({ { "packet_type", "multicast_gather" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out { packets.Add({ { "packet_type", "multicast_frame" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out { packets.Add({ { "packet_type", "push_direct_paths" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_user_message_out { packets.Add({ { "packet_type", "user_message" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_remote_trace_out { packets.Add({ { "packet_type", "remote_trace" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out { packets.Add({ { "packet_type", "path_negotiation_request" }, { "direction", "tx" } }) };
// Packet Error Counts
prometheus::simpleapi::counter_family_t packet_errors { "zt_packet_error", "ZeroTier packet errors" };
// Packet Error Counts
prometheus::simpleapi::counter_family_t packet_errors
{ "zt_packet_error", "ZeroTier packet errors"};
// Incoming Error Counts
prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in { packet_errors.Add({ { "error_type", "obj_not_found" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in { packet_errors.Add({ { "error_type", "unsupported_operation" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in { packet_errors.Add({ { "error_type", "identity_collision" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in { packet_errors.Add({ { "error_type", "need_membership_certificate" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in { packet_errors.Add({ { "error_type", "network_access_denied" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in { packet_errors.Add({ { "error_type", "unwanted_multicast" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in { packet_errors.Add({ { "error_type", "authentication_required" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in { packet_errors.Add({ { "error_type", "internal_server_error" }, { "direction", "rx" } }) };
// Incoming Error Counts
prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in
{ packet_errors.Add({{"error_type", "obj_not_found"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in
{ packet_errors.Add({{"error_type", "unsupported_operation"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in
{ packet_errors.Add({{"error_type", "identity_collision"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in
{ packet_errors.Add({{"error_type", "need_membership_certificate"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in
{ packet_errors.Add({{"error_type", "network_access_denied"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in
{ packet_errors.Add({{"error_type", "unwanted_multicast"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in
{ packet_errors.Add({{"error_type", "authentication_required"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in
{ packet_errors.Add({{"error_type", "internal_server_error"}, {"direction", "rx"}}) };
// Outgoing Error Counts
prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out { packet_errors.Add({ { "error_type", "obj_not_found" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out { packet_errors.Add({ { "error_type", "unsupported_operation" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out { packet_errors.Add({ { "error_type", "identity_collision" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out { packet_errors.Add({ { "error_type", "need_membership_certificate" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out { packet_errors.Add({ { "error_type", "network_access_denied" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out { packet_errors.Add({ { "error_type", "unwanted_multicast" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out { packet_errors.Add({ { "error_type", "authentication_required" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out { packet_errors.Add({ { "error_type", "internal_server_error" }, { "direction", "tx" } }) };
// Outgoing Error Counts
prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out
{ packet_errors.Add({{"error_type", "obj_not_found"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out
{ packet_errors.Add({{"error_type", "unsupported_operation"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out
{ packet_errors.Add({{"error_type", "identity_collision"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out
{ packet_errors.Add({{"error_type", "need_membership_certificate"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out
{ packet_errors.Add({{"error_type", "network_access_denied"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out
{ packet_errors.Add({{"error_type", "unwanted_multicast"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out
{ packet_errors.Add({{"error_type", "authentication_required"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out
{ packet_errors.Add({{"error_type", "internal_server_error"}, {"direction", "tx"}}) };
// Data Sent/Received Metrics
prometheus::simpleapi::counter_family_t data { "zt_data", "number of bytes ZeroTier has transmitted or received" };
prometheus::simpleapi::counter_metric_t udp_recv { data.Add({ { "protocol", "udp" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t udp_send { data.Add({ { "protocol", "udp" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t tcp_send { data.Add({ { "protocol", "tcp" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t tcp_recv { data.Add({ { "protocol", "tcp" }, { "direction", "rx" } }) };
// Data Sent/Received Metrics
prometheus::simpleapi::counter_family_t data
{ "zt_data", "number of bytes ZeroTier has transmitted or received" };
prometheus::simpleapi::counter_metric_t udp_recv
{ data.Add({{"protocol","udp"},{"direction","rx"}}) };
prometheus::simpleapi::counter_metric_t udp_send
{ data.Add({{"protocol","udp"},{"direction","tx"}}) };
prometheus::simpleapi::counter_metric_t tcp_send
{ data.Add({{"protocol","tcp"},{"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t tcp_recv
{ data.Add({{"protocol","tcp"},{"direction", "rx"}}) };
// Network Metrics
prometheus::simpleapi::gauge_metric_t network_num_joined { "zt_num_networks", "number of networks this instance is joined to" };
prometheus::simpleapi::gauge_family_t network_num_multicast_groups { "zt_network_multicast_groups_subscribed", "number of multicast groups networks are subscribed to" };
prometheus::simpleapi::counter_family_t network_packets { "zt_network_packets", "number of incoming/outgoing packets per network" };
// Network Metrics
prometheus::simpleapi::gauge_metric_t network_num_joined
{ "zt_num_networks", "number of networks this instance is joined to" };
prometheus::simpleapi::gauge_family_t network_num_multicast_groups
{ "zt_network_multicast_groups_subscribed", "number of multicast groups networks are subscribed to" };
prometheus::simpleapi::counter_family_t network_packets
{ "zt_network_packets", "number of incoming/outgoing packets per network" };
#ifndef ZT_NO_PEER_METRICS
// PeerMetrics
prometheus::CustomFamily<prometheus::Histogram<uint64_t>> &peer_latency =
prometheus::Builder<prometheus::Histogram<uint64_t>>()
.Name("zt_peer_latency")
.Help("peer latency (ms)")
.Register(prometheus::simpleapi::registry);
prometheus::simpleapi::gauge_family_t peer_path_count
{ "zt_peer_path_count", "number of paths to peer" };
prometheus::simpleapi::counter_family_t peer_packets
{ "zt_peer_packets", "number of packets to/from a peer" };
prometheus::simpleapi::counter_family_t peer_packet_errors
{ "zt_peer_packet_errors" , "number of incoming packet errors from a peer" };
// PeerMetrics
prometheus::CustomFamily<prometheus::Histogram<uint64_t> >& peer_latency = prometheus::Builder<prometheus::Histogram<uint64_t> >().Name("zt_peer_latency").Help("peer latency (ms)").Register(prometheus::simpleapi::registry);
prometheus::simpleapi::gauge_family_t peer_path_count { "zt_peer_path_count", "number of paths to peer" };
prometheus::simpleapi::counter_family_t peer_packets { "zt_peer_packets", "number of packets to/from a peer" };
prometheus::simpleapi::counter_family_t peer_packet_errors { "zt_peer_packet_errors", "number of incoming packet errors from a peer" };
#endif
// General Controller Metrics
prometheus::simpleapi::gauge_metric_t network_count
{"controller_network_count", "number of networks the controller is serving"};
prometheus::simpleapi::gauge_metric_t member_count
{"controller_member_count", "number of network members the controller is serving"};
prometheus::simpleapi::counter_metric_t network_changes
{"controller_network_change_count", "number of times a network configuration is changed"};
prometheus::simpleapi::counter_metric_t member_changes
{"controller_member_change_count", "number of times a network member configuration is changed"};
prometheus::simpleapi::counter_metric_t member_auths
{"controller_member_auth_count", "number of network member auths"};
prometheus::simpleapi::counter_metric_t member_deauths
{"controller_member_deauth_count", "number of network member deauths"};
// General Controller Metrics
prometheus::simpleapi::gauge_metric_t network_count { "controller_network_count", "number of networks the controller is serving" };
prometheus::simpleapi::gauge_metric_t member_count { "controller_member_count", "number of network members the controller is serving" };
prometheus::simpleapi::counter_metric_t network_changes { "controller_network_change_count", "number of times a network configuration is changed" };
prometheus::simpleapi::counter_metric_t member_changes { "controller_member_change_count", "number of times a network member configuration is changed" };
prometheus::simpleapi::counter_metric_t member_auths { "controller_member_auth_count", "number of network member auths" };
prometheus::simpleapi::counter_metric_t member_deauths { "controller_member_deauth_count", "number of network member deauths" };
prometheus::simpleapi::gauge_metric_t network_config_request_queue_size
{ "controller_network_config_request_queue", "number of entries in the request queue for network configurations" };
prometheus::simpleapi::counter_metric_t sso_expiration_checks
{ "controller_sso_expiration_checks", "number of sso expiration checks done" };
prometheus::simpleapi::gauge_metric_t network_config_request_queue_size { "controller_network_config_request_queue", "number of entries in the request queue for network configurations" };
prometheus::simpleapi::counter_metric_t sso_member_deauth
{ "controller_sso_timeouts", "number of sso timeouts" };
prometheus::simpleapi::counter_metric_t sso_expiration_checks { "controller_sso_expiration_checks", "number of sso expiration checks done" };
prometheus::simpleapi::counter_metric_t network_config_request
{ "controller_network_config_request", "count of config requests handled" };
prometheus::simpleapi::gauge_metric_t network_config_request_threads
{ "controller_network_config_request_threads", "number of active network config handling threads" };
prometheus::simpleapi::counter_metric_t db_get_network
{ "controller_db_get_network", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_and_member
{ "controller_db_get_network_and_member", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary
{ "controller_db_get_networK_and_member_summary", "counter" };
prometheus::simpleapi::counter_metric_t db_get_member_list
{ "controller_db_get_member_list", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_list
{ "controller_db_get_network_list", "counter" };
prometheus::simpleapi::counter_metric_t db_member_change
{ "controller_db_member_change", "counter" };
prometheus::simpleapi::counter_metric_t db_network_change
{ "controller_db_network_change", "counter" };
prometheus::simpleapi::counter_metric_t sso_member_deauth { "controller_sso_timeouts", "number of sso timeouts" };
prometheus::simpleapi::counter_metric_t network_config_request { "controller_network_config_request", "count of config requests handled" };
prometheus::simpleapi::gauge_metric_t network_config_request_threads { "controller_network_config_request_threads", "number of active network config handling threads" };
prometheus::simpleapi::counter_metric_t db_get_network { "controller_db_get_network", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_and_member { "controller_db_get_network_and_member", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary { "controller_db_get_networK_and_member_summary", "counter" };
prometheus::simpleapi::counter_metric_t db_get_member_list { "controller_db_get_member_list", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_list { "controller_db_get_network_list", "counter" };
prometheus::simpleapi::counter_metric_t db_member_change { "controller_db_member_change", "counter" };
prometheus::simpleapi::counter_metric_t db_network_change { "controller_db_network_change", "counter" };
#ifdef ZT_CONTROLLER_USE_LIBPQ
// Central Controller Metrics
prometheus::simpleapi::counter_metric_t pgsql_mem_notification
{ "controller_pgsql_member_notifications_received", "number of member change notifications received via pgsql NOTIFY" };
prometheus::simpleapi::counter_metric_t pgsql_net_notification
{ "controller_pgsql_network_notifications_received", "number of network change notifications received via pgsql NOTIFY" };
prometheus::simpleapi::counter_metric_t pgsql_node_checkin
{ "controller_pgsql_node_checkin_count", "number of node check-ins (pgsql)" };
prometheus::simpleapi::counter_metric_t pgsql_commit_ticks
{ "controller_pgsql_commit_ticks", "number of commit ticks run (pgsql)" };
prometheus::simpleapi::counter_metric_t db_get_sso_info
{ "controller_db_get_sso_info", "counter" };
// Central Controller Metrics
prometheus::simpleapi::counter_metric_t pgsql_mem_notification { "controller_pgsql_member_notifications_received", "number of member change notifications received via pgsql NOTIFY" };
prometheus::simpleapi::counter_metric_t pgsql_net_notification { "controller_pgsql_network_notifications_received", "number of network change notifications received via pgsql NOTIFY" };
prometheus::simpleapi::counter_metric_t pgsql_node_checkin { "controller_pgsql_node_checkin_count", "number of node check-ins (pgsql)" };
prometheus::simpleapi::counter_metric_t pgsql_commit_ticks { "controller_pgsql_commit_ticks", "number of commit ticks run (pgsql)" };
prometheus::simpleapi::counter_metric_t db_get_sso_info { "controller_db_get_sso_info", "counter" };
prometheus::simpleapi::counter_metric_t redis_mem_notification
{ "controller_redis_member_notifications_received", "number of member change notifications received via redis" };
prometheus::simpleapi::counter_metric_t redis_net_notification
{ "controller_redis_network_notifications_received", "number of network change notifications received via redis" };
prometheus::simpleapi::counter_metric_t redis_node_checkin
{ "controller_redis_node_checkin_count", "number of node check-ins (redis)" };
prometheus::simpleapi::counter_metric_t redis_mem_notification { "controller_redis_member_notifications_received", "number of member change notifications received via redis" };
prometheus::simpleapi::counter_metric_t redis_net_notification { "controller_redis_network_notifications_received", "number of network change notifications received via redis" };
prometheus::simpleapi::counter_metric_t redis_node_checkin { "controller_redis_node_checkin_count", "number of node check-ins (redis)" };
// Central DB Pool Metrics
prometheus::simpleapi::counter_metric_t conn_counter
{ "controller_pgsql_connections_created", "number of pgsql connections created"};
prometheus::simpleapi::counter_metric_t max_pool_size
{ "controller_pgsql_max_conn_pool_size", "max connection pool size for postgres"};
prometheus::simpleapi::counter_metric_t min_pool_size
{ "controller_pgsql_min_conn_pool_size", "minimum connection pool size for postgres" };
prometheus::simpleapi::gauge_metric_t pool_avail
{ "controller_pgsql_available_conns", "number of available postgres connections" };
prometheus::simpleapi::gauge_metric_t pool_in_use
{ "controller_pgsql_in_use_conns", "number of postgres database connections in use" };
prometheus::simpleapi::counter_metric_t pool_errors
{ "controller_pgsql_connection_errors", "number of connection errors the connection pool has seen" };
// Central DB Pool Metrics
prometheus::simpleapi::counter_metric_t conn_counter { "controller_pgsql_connections_created", "number of pgsql connections created" };
prometheus::simpleapi::counter_metric_t max_pool_size { "controller_pgsql_max_conn_pool_size", "max connection pool size for postgres" };
prometheus::simpleapi::counter_metric_t min_pool_size { "controller_pgsql_min_conn_pool_size", "minimum connection pool size for postgres" };
prometheus::simpleapi::gauge_metric_t pool_avail { "controller_pgsql_available_conns", "number of available postgres connections" };
prometheus::simpleapi::gauge_metric_t pool_in_use { "controller_pgsql_in_use_conns", "number of postgres database connections in use" };
prometheus::simpleapi::counter_metric_t pool_errors { "controller_pgsql_connection_errors", "number of connection errors the connection pool has seen" };
#endif
}
}
} // namespace Metrics
} // namespace ZeroTier

View file

@ -12,155 +12,152 @@
#ifndef METRICS_H_
#define METRICS_H_
#include <prometheus/simpleapi.h>
#include <prometheus/histogram.h>
#include <prometheus/simpleapi.h>
namespace prometheus {
namespace simpleapi {
extern std::shared_ptr<Registry> registry_ptr;
}
namespace simpleapi {
extern std::shared_ptr<Registry> registry_ptr;
}
} // namespace prometheus
namespace ZeroTier {
namespace Metrics {
// Packet Type Counts
extern prometheus::simpleapi::counter_family_t packets;
namespace Metrics {
// Packet Type Counts
extern prometheus::simpleapi::counter_family_t packets;
// incoming packets
extern prometheus::simpleapi::counter_metric_t pkt_nop_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_in;
extern prometheus::simpleapi::counter_metric_t pkt_ack_in;
extern prometheus::simpleapi::counter_metric_t pkt_qos_in;
extern prometheus::simpleapi::counter_metric_t pkt_hello_in;
extern prometheus::simpleapi::counter_metric_t pkt_ok_in;
extern prometheus::simpleapi::counter_metric_t pkt_whois_in;
extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_in;
extern prometheus::simpleapi::counter_metric_t pkt_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_echo_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in;
extern prometheus::simpleapi::counter_metric_t pkt_user_message_in;
extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_in;
extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in;
// incoming packets
extern prometheus::simpleapi::counter_metric_t pkt_nop_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_in;
extern prometheus::simpleapi::counter_metric_t pkt_ack_in;
extern prometheus::simpleapi::counter_metric_t pkt_qos_in;
extern prometheus::simpleapi::counter_metric_t pkt_hello_in;
extern prometheus::simpleapi::counter_metric_t pkt_ok_in;
extern prometheus::simpleapi::counter_metric_t pkt_whois_in;
extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_in;
extern prometheus::simpleapi::counter_metric_t pkt_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_echo_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in;
extern prometheus::simpleapi::counter_metric_t pkt_user_message_in;
extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_in;
extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in;
// outgoing packets
extern prometheus::simpleapi::counter_metric_t pkt_nop_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_out;
extern prometheus::simpleapi::counter_metric_t pkt_ack_out;
extern prometheus::simpleapi::counter_metric_t pkt_qos_out;
extern prometheus::simpleapi::counter_metric_t pkt_hello_out;
extern prometheus::simpleapi::counter_metric_t pkt_ok_out;
extern prometheus::simpleapi::counter_metric_t pkt_whois_out;
extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_out;
extern prometheus::simpleapi::counter_metric_t pkt_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_echo_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out;
extern prometheus::simpleapi::counter_metric_t pkt_user_message_out;
extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_out;
extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out;
// outgoing packets
extern prometheus::simpleapi::counter_metric_t pkt_nop_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_out;
extern prometheus::simpleapi::counter_metric_t pkt_ack_out;
extern prometheus::simpleapi::counter_metric_t pkt_qos_out;
extern prometheus::simpleapi::counter_metric_t pkt_hello_out;
extern prometheus::simpleapi::counter_metric_t pkt_ok_out;
extern prometheus::simpleapi::counter_metric_t pkt_whois_out;
extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_out;
extern prometheus::simpleapi::counter_metric_t pkt_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_echo_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out;
extern prometheus::simpleapi::counter_metric_t pkt_user_message_out;
extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_out;
extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out;
// Packet Error Counts
extern prometheus::simpleapi::counter_family_t packet_errors;
// Packet Error Counts
extern prometheus::simpleapi::counter_family_t packet_errors;
// incoming errors
extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in;
// incoming errors
extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in;
// outgoing errors
extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out;
// outgoing errors
extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out;
// Data Sent/Received Metrics
extern prometheus::simpleapi::counter_family_t data;
extern prometheus::simpleapi::counter_metric_t udp_send;
extern prometheus::simpleapi::counter_metric_t udp_recv;
extern prometheus::simpleapi::counter_metric_t tcp_send;
extern prometheus::simpleapi::counter_metric_t tcp_recv;
// Data Sent/Received Metrics
extern prometheus::simpleapi::counter_family_t data;
extern prometheus::simpleapi::counter_metric_t udp_send;
extern prometheus::simpleapi::counter_metric_t udp_recv;
extern prometheus::simpleapi::counter_metric_t tcp_send;
extern prometheus::simpleapi::counter_metric_t tcp_recv;
// Network Metrics
extern prometheus::simpleapi::gauge_metric_t network_num_joined;
extern prometheus::simpleapi::gauge_family_t network_num_multicast_groups;
extern prometheus::simpleapi::counter_family_t network_packets;
// Network Metrics
extern prometheus::simpleapi::gauge_metric_t network_num_joined;
extern prometheus::simpleapi::gauge_family_t network_num_multicast_groups;
extern prometheus::simpleapi::counter_family_t network_packets;
#ifndef ZT_NO_PEER_METRICS
// Peer Metrics
extern prometheus::CustomFamily<prometheus::Histogram<uint64_t>> &peer_latency;
extern prometheus::simpleapi::gauge_family_t peer_path_count;
extern prometheus::simpleapi::counter_family_t peer_packets;
extern prometheus::simpleapi::counter_family_t peer_packet_errors;
// Peer Metrics
extern prometheus::CustomFamily<prometheus::Histogram<uint64_t> >& peer_latency;
extern prometheus::simpleapi::gauge_family_t peer_path_count;
extern prometheus::simpleapi::counter_family_t peer_packets;
extern prometheus::simpleapi::counter_family_t peer_packet_errors;
#endif
// General Controller Metrics
extern prometheus::simpleapi::gauge_metric_t network_count;
extern prometheus::simpleapi::gauge_metric_t member_count;
extern prometheus::simpleapi::counter_metric_t network_changes;
extern prometheus::simpleapi::counter_metric_t member_changes;
extern prometheus::simpleapi::counter_metric_t member_auths;
extern prometheus::simpleapi::counter_metric_t member_deauths;
// General Controller Metrics
extern prometheus::simpleapi::gauge_metric_t network_count;
extern prometheus::simpleapi::gauge_metric_t member_count;
extern prometheus::simpleapi::counter_metric_t network_changes;
extern prometheus::simpleapi::counter_metric_t member_changes;
extern prometheus::simpleapi::counter_metric_t member_auths;
extern prometheus::simpleapi::counter_metric_t member_deauths;
extern prometheus::simpleapi::gauge_metric_t network_config_request_queue_size;
extern prometheus::simpleapi::counter_metric_t sso_expiration_checks;
extern prometheus::simpleapi::counter_metric_t sso_member_deauth;
extern prometheus::simpleapi::counter_metric_t network_config_request;
extern prometheus::simpleapi::gauge_metric_t network_config_request_threads;
extern prometheus::simpleapi::counter_metric_t db_get_network;
extern prometheus::simpleapi::counter_metric_t db_get_network_and_member;
extern prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary;
extern prometheus::simpleapi::counter_metric_t db_get_member_list;
extern prometheus::simpleapi::counter_metric_t db_get_network_list;
extern prometheus::simpleapi::counter_metric_t db_member_change;
extern prometheus::simpleapi::counter_metric_t db_network_change;
extern prometheus::simpleapi::gauge_metric_t network_config_request_queue_size;
extern prometheus::simpleapi::counter_metric_t sso_expiration_checks;
extern prometheus::simpleapi::counter_metric_t sso_member_deauth;
extern prometheus::simpleapi::counter_metric_t network_config_request;
extern prometheus::simpleapi::gauge_metric_t network_config_request_threads;
extern prometheus::simpleapi::counter_metric_t db_get_network;
extern prometheus::simpleapi::counter_metric_t db_get_network_and_member;
extern prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary;
extern prometheus::simpleapi::counter_metric_t db_get_member_list;
extern prometheus::simpleapi::counter_metric_t db_get_network_list;
extern prometheus::simpleapi::counter_metric_t db_member_change;
extern prometheus::simpleapi::counter_metric_t db_network_change;
#ifdef ZT_CONTROLLER_USE_LIBPQ
// Central Controller Metrics
extern prometheus::simpleapi::counter_metric_t pgsql_mem_notification;
extern prometheus::simpleapi::counter_metric_t pgsql_net_notification;
extern prometheus::simpleapi::counter_metric_t pgsql_node_checkin;
extern prometheus::simpleapi::counter_metric_t pgsql_commit_ticks;
extern prometheus::simpleapi::counter_metric_t db_get_sso_info;
extern prometheus::simpleapi::counter_metric_t redis_mem_notification;
extern prometheus::simpleapi::counter_metric_t redis_net_notification;
extern prometheus::simpleapi::counter_metric_t redis_node_checkin;
// Central Controller Metrics
extern prometheus::simpleapi::counter_metric_t pgsql_mem_notification;
extern prometheus::simpleapi::counter_metric_t pgsql_net_notification;
extern prometheus::simpleapi::counter_metric_t pgsql_node_checkin;
extern prometheus::simpleapi::counter_metric_t pgsql_commit_ticks;
extern prometheus::simpleapi::counter_metric_t db_get_sso_info;
extern prometheus::simpleapi::counter_metric_t redis_mem_notification;
extern prometheus::simpleapi::counter_metric_t redis_net_notification;
extern prometheus::simpleapi::counter_metric_t redis_node_checkin;
// Central DB Pool Metrics
extern prometheus::simpleapi::counter_metric_t conn_counter;
extern prometheus::simpleapi::counter_metric_t max_pool_size;
extern prometheus::simpleapi::counter_metric_t min_pool_size;
extern prometheus::simpleapi::gauge_metric_t pool_avail;
extern prometheus::simpleapi::gauge_metric_t pool_in_use;
extern prometheus::simpleapi::counter_metric_t pool_errors;
// Central DB Pool Metrics
extern prometheus::simpleapi::counter_metric_t conn_counter;
extern prometheus::simpleapi::counter_metric_t max_pool_size;
extern prometheus::simpleapi::counter_metric_t min_pool_size;
extern prometheus::simpleapi::gauge_metric_t pool_avail;
extern prometheus::simpleapi::gauge_metric_t pool_in_use;
extern prometheus::simpleapi::counter_metric_t pool_errors;
#endif
} // namespace Metrics
}// namespace ZeroTier
} // namespace Metrics
} // namespace ZeroTier
#endif // METRICS_H_
#endif // METRICS_H_

View file

@ -14,10 +14,10 @@
#ifndef ZT_MULTICASTGROUP_HPP
#define ZT_MULTICASTGROUP_HPP
#include <stdint.h>
#include "MAC.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include <stdint.h>
namespace ZeroTier {
@ -36,18 +36,13 @@ namespace ZeroTier {
*
* MulticastGroup behaves as an immutable value object.
*/
class MulticastGroup
{
public:
MulticastGroup() :
_mac(),
_adi(0)
class MulticastGroup {
public:
MulticastGroup() : _mac(), _adi(0)
{
}
MulticastGroup(const MAC &m,uint32_t a) :
_mac(m),
_adi(a)
MulticastGroup(const MAC& m, uint32_t a) : _mac(m), _adi(a)
{
}
@ -57,21 +52,22 @@ public:
* @param ip IP address (port field is ignored)
* @return Multicast group for ARP/NDP
*/
static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip)
static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress& ip)
{
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()) {
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);
const unsigned char* a = (const unsigned char*)ip.rawIpData();
return MulticastGroup(MAC(0x33, 0x33, 0xff, a[13], a[14], a[15]), 0);
}
return MulticastGroup();
}
@ -79,35 +75,60 @@ public:
/**
* @return Multicast address
*/
inline const MAC &mac() const { return _mac; }
inline const MAC& mac() const
{
return _mac;
}
/**
* @return Additional distinguishing information
*/
inline uint32_t adi() const { return _adi; }
inline uint32_t adi() const
{
return _adi;
}
inline unsigned long hashCode() const { return (_mac.hashCode() ^ (unsigned long)_adi); }
inline unsigned long hashCode() const
{
return (_mac.hashCode() ^ (unsigned long)_adi);
}
inline bool operator==(const MulticastGroup &g) const { return ((_mac == g._mac)&&(_adi == g._adi)); }
inline bool operator!=(const MulticastGroup &g) const { return ((_mac != g._mac)||(_adi != g._adi)); }
inline bool operator<(const MulticastGroup &g) const
inline bool operator==(const MulticastGroup& g) const
{
return ((_mac == g._mac) && (_adi == g._adi));
}
inline bool operator!=(const MulticastGroup& g) const
{
return ((_mac != g._mac) || (_adi != g._adi));
}
inline bool operator<(const MulticastGroup& g) const
{
if (_mac < g._mac) {
return true;
} else if (_mac == g._mac) {
}
else if (_mac == g._mac) {
return (_adi < g._adi);
}
return false;
}
inline bool operator>(const MulticastGroup &g) const { return (g < *this); }
inline bool operator<=(const MulticastGroup &g) const { return !(g < *this); }
inline bool operator>=(const MulticastGroup &g) const { return !(*this < g); }
inline bool operator>(const MulticastGroup& g) const
{
return (g < *this);
}
inline bool operator<=(const MulticastGroup& g) const
{
return ! (g < *this);
}
inline bool operator>=(const MulticastGroup& g) const
{
return ! (*this < g);
}
private:
private:
MAC _mac;
uint32_t _adi;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,25 +11,24 @@
*/
/****/
#include <algorithm>
#include "Constants.hpp"
#include "RuntimeEnvironment.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"
#include "Constants.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
#include <algorithm>
namespace ZeroTier {
Multicaster::Multicaster(const RuntimeEnvironment *renv) :
RR(renv),
_groups(32)
Multicaster::Multicaster(const RuntimeEnvironment* renv) : RR(renv), _groups(32)
{
}
@ -37,24 +36,24 @@ Multicaster::~Multicaster()
{
}
void Multicaster::addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown)
void Multicaster::addMultiple(void* tPtr, int64_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);
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)];
MulticastGroupStatus& gs = _groups[Multicaster::Key(nwid, mg)];
while (p != e) {
_add(tPtr,now,nwid,mg,gs,Address(p,5));
_add(tPtr, now, nwid, mg, gs, Address(p, 5));
p += 5;
}
}
void Multicaster::remove(uint64_t nwid,const MulticastGroup &mg,const Address &member)
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));
MulticastGroupStatus* s = _groups.get(Multicaster::Key(nwid, mg));
if (s) {
for(std::vector<MulticastGroupMember>::iterator m(s->members.begin());m!=s->members.end();++m) {
for (std::vector<MulticastGroupMember>::iterator m(s->members.begin()); m != s->members.end(); ++m) {
if (m->address == member) {
s->members.erase(m);
break;
@ -63,26 +62,27 @@ void Multicaster::remove(uint64_t nwid,const MulticastGroup &mg,const Address &m
}
}
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 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];
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) {
if (! limit) {
return 0;
} else if (limit > 0xffff) {
}
else if (limit > 0xffff) {
limit = 0xffff;
}
const unsigned int totalAt = appendTo.size();
appendTo.addSize(4); // sizeof(uint32_t)
appendTo.addSize(4); // sizeof(uint32_t)
const unsigned int addedAt = appendTo.size();
appendTo.addSize(2); // sizeof(uint16_t)
appendTo.addSize(2); // sizeof(uint16_t)
{ // Return myself if I am a member of this group
{ // Return myself if I am a member of this group
SharedPtr<Network> network(RR->node->network(nwid));
if ((network)&&(network->subscribedToMulticastGroup(mg,true))) {
if ((network) && (network->subscribedToMulticastGroup(mg, true))) {
RR->identity.address().appendTo(appendTo);
++totalKnown;
++added;
@ -91,19 +91,19 @@ unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const
Mutex::Lock _l(_groups_m);
const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg));
if ((s)&&(!s->members.empty())) {
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_PROTO_MAX_PACKET_LENGTH)) {
while ((added < limit) && (k < s->members.size()) && ((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_PROTO_MAX_PACKET_LENGTH)) {
rptr = (unsigned int)RR->node->prng();
restart_member_scan:
restart_member_scan:
a = s->members[rptr % (unsigned int)s->members.size()].address.toInt();
for(i=0;i<k;++i) {
for (i = 0; i < k; ++i) {
if (picked[i] == a) {
++rptr;
goto restart_member_scan;
@ -111,8 +111,8 @@ 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);
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);
@ -123,21 +123,21 @@ restart_member_scan:
}
}
appendTo.setAt(totalAt,(uint32_t)totalKnown);
appendTo.setAt(addedAt,(uint16_t)added);
appendTo.setAt(totalAt, (uint32_t)totalKnown);
appendTo.setAt(addedAt, (uint16_t)added);
return added;
}
std::vector<Address> Multicaster::getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const
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) {
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) {
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;
@ -146,19 +146,10 @@ std::vector<Address> Multicaster::getMembers(uint64_t nwid,const MulticastGroup
return ls;
}
void Multicaster::send(
void *tPtr,
int64_t now,
const SharedPtr<Network> &network,
const Address &origin,
const MulticastGroup &mg,
const MAC &src,
unsigned int etherType,
const void *data,
unsigned int len)
void Multicaster::send(void* tPtr, int64_t now, const SharedPtr<Network>& network, const Address& origin, const MulticastGroup& mg, const MAC& src, unsigned int etherType, const void* data, unsigned int len)
{
unsigned long idxbuf[4096];
unsigned long *indexes = idxbuf;
unsigned long* indexes = idxbuf;
// If we're in hub-and-spoke designated multicast replication mode, see if we
// have a multicast replicator active. If so, pick the best and send it
@ -168,19 +159,19 @@ void Multicaster::send(
// the current protocol and could be fixed, but fixing it would add more
// complexity than the fix is probably worth. Bridges are generally high
// bandwidth nodes.
if (!network->config().isActiveBridge(RR->identity.address())) {
if (! network->config().isActiveBridge(RR->identity.address())) {
Address multicastReplicators[ZT_MAX_NETWORK_SPECIALISTS];
const unsigned int multicastReplicatorCount = network->config().multicastReplicators(multicastReplicators);
if (multicastReplicatorCount) {
if (std::find(multicastReplicators,multicastReplicators + multicastReplicatorCount,RR->identity.address()) == (multicastReplicators + multicastReplicatorCount)) {
if (std::find(multicastReplicators, multicastReplicators + multicastReplicatorCount, RR->identity.address()) == (multicastReplicators + multicastReplicatorCount)) {
SharedPtr<Peer> bestMulticastReplicator;
SharedPtr<Path> bestMulticastReplicatorPath;
unsigned int bestMulticastReplicatorLatency = 0xffff;
for(unsigned int i=0;i<multicastReplicatorCount;++i) {
for (unsigned int i = 0; i < multicastReplicatorCount; ++i) {
const SharedPtr<Peer> p(RR->topology->getPeerNoCache(multicastReplicators[i]));
if ((p)&&(p->isAlive(now))) {
const SharedPtr<Path> pp(p->getAppropriatePath(now,false));
if ((pp)&&(pp->latency() < bestMulticastReplicatorLatency)) {
if ((p) && (p->isAlive(now))) {
const SharedPtr<Path> pp(p->getAppropriatePath(now, false));
if ((pp) && (pp->latency() < bestMulticastReplicatorLatency)) {
bestMulticastReplicatorLatency = pp->latency();
bestMulticastReplicatorPath = pp;
bestMulticastReplicator = p;
@ -188,20 +179,20 @@ void Multicaster::send(
}
}
if (bestMulticastReplicator) {
Packet outp(bestMulticastReplicator->address(),RR->identity.address(),Packet::VERB_MULTICAST_FRAME);
Packet outp(bestMulticastReplicator->address(), RR->identity.address(), Packet::VERB_MULTICAST_FRAME);
outp.append((uint64_t)network->id());
outp.append((uint8_t)0x0c); // includes source MAC | please replicate
((src) ? src : MAC(RR->identity.address(),network->id())).appendTo(outp);
outp.append((uint8_t)0x0c); // includes source MAC | please replicate
((src) ? src : MAC(RR->identity.address(), network->id())).appendTo(outp);
mg.mac().appendTo(outp);
outp.append((uint32_t)mg.adi());
outp.append((uint16_t)etherType);
outp.append(data,len);
if (!network->config().disableCompression()) {
outp.append(data, len);
if (! network->config().disableCompression()) {
outp.compress();
}
outp.armor(bestMulticastReplicator->key(),true,bestMulticastReplicator->aesKeysIfSupported());
outp.armor(bestMulticastReplicator->key(), true, bestMulticastReplicator->aesKeysIfSupported());
Metrics::pkt_multicast_frame_out++;
bestMulticastReplicatorPath->send(RR,tPtr,outp.data(),outp.size(),now);
bestMulticastReplicatorPath->send(RR, tPtr, outp.data(), outp.size(), now);
return;
}
}
@ -210,19 +201,19 @@ void Multicaster::send(
try {
Mutex::Lock _l(_groups_m);
MulticastGroupStatus &gs = _groups[Multicaster::Key(network->id(),mg)];
MulticastGroupStatus& gs = _groups[Multicaster::Key(network->id(), mg)];
if (!gs.members.empty()) {
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) {
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) {
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];
@ -244,7 +235,7 @@ void Multicaster::send(
network->id(),
network->config().disableCompression(),
limit,
1, // we'll still gather a little from peers to keep multicast list fresh
1, // we'll still gather a little from peers to keep multicast list fresh
src,
mg,
etherType,
@ -253,9 +244,9 @@ void Multicaster::send(
unsigned int count = 0;
for(unsigned int i=0;i<activeBridgeCount;++i) {
if ((activeBridges[i] != RR->identity.address())&&(activeBridges[i] != origin)) {
out.sendOnly(RR,tPtr,activeBridges[i]); // optimization: don't use dedup log if it's a one-pass send
for (unsigned int i = 0; i < activeBridgeCount; ++i) {
if ((activeBridges[i] != RR->identity.address()) && (activeBridges[i] != origin)) {
out.sendOnly(RR, tPtr, activeBridges[i]); // optimization: don't use dedup log if it's a one-pass send
if (++count >= limit) {
break;
}
@ -263,14 +254,15 @@ void Multicaster::send(
}
unsigned long idx = 0;
while ((count < limit)&&(idx < gs.members.size())) {
while ((count < limit) && (idx < gs.members.size())) {
const Address ma(gs.members[indexes[idx++]].address);
if ((std::find(activeBridges,activeBridges + activeBridgeCount,ma) == (activeBridges + activeBridgeCount))&&(ma != origin)) {
out.sendOnly(RR,tPtr,ma); // optimization: don't use dedup log if it's a one-pass send
if ((std::find(activeBridges, activeBridges + activeBridgeCount, ma) == (activeBridges + activeBridgeCount)) && (ma != origin)) {
out.sendOnly(RR, tPtr, ma); // optimization: don't use dedup log if it's a one-pass send
++count;
}
}
} else {
}
else {
while (gs.txQueue.size() >= ZT_TX_QUEUE_SIZE) {
gs.txQueue.pop_front();
}
@ -278,7 +270,7 @@ void Multicaster::send(
const unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1;
int timerScale = RR->node->lowBandwidthModeEnabled() ? 3 : 1;
if ((gs.members.empty())||((now - gs.lastExplicitGather) >= (ZT_MULTICAST_EXPLICIT_GATHER_DELAY * timerScale))) {
if ((gs.members.empty()) || ((now - gs.lastExplicitGather) >= (ZT_MULTICAST_EXPLICIT_GATHER_DELAY * timerScale))) {
gs.lastExplicitGather = now;
Address explicitGatherPeers[16];
@ -294,10 +286,10 @@ void Multicaster::send(
Address ac[ZT_MAX_NETWORK_SPECIALISTS];
const unsigned int accnt = network->config().alwaysContactAddresses(ac);
unsigned int shuffled[ZT_MAX_NETWORK_SPECIALISTS];
for(unsigned int i=0;i<accnt;++i) {
for (unsigned int i = 0; i < accnt; ++i) {
shuffled[i] = i;
}
for(unsigned int i=0,k=accnt>>1;i<k;++i) {
for (unsigned int i = 0, k = accnt >> 1; i < k; ++i) {
const uint64_t x = RR->node->prng();
const unsigned int x1 = shuffled[(unsigned int)x % accnt];
const unsigned int x2 = shuffled[(unsigned int)(x >> 32) % accnt];
@ -305,7 +297,7 @@ void Multicaster::send(
shuffled[x1] = shuffled[x2];
shuffled[x2] = tmp;
}
for(unsigned int i=0;i<accnt;++i) {
for (unsigned int i = 0; i < accnt; ++i) {
explicitGatherPeers[numExplicitGatherPeers++] = ac[shuffled[i]];
if (numExplicitGatherPeers == 16) {
break;
@ -313,7 +305,7 @@ void Multicaster::send(
}
std::vector<Address> anchors(network->config().anchors());
for(std::vector<Address>::const_iterator a(anchors.begin());a!=anchors.end();++a) {
for (std::vector<Address>::const_iterator a(anchors.begin()); a != anchors.end(); ++a) {
if (*a != RR->identity.address()) {
explicitGatherPeers[numExplicitGatherPeers++] = *a;
if (numExplicitGatherPeers == 16) {
@ -322,9 +314,9 @@ void Multicaster::send(
}
}
for(unsigned int k=0;k<numExplicitGatherPeers;++k) {
const CertificateOfMembership *com = (network) ? ((network->config().com) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0;
Packet outp(explicitGatherPeers[k],RR->identity.address(),Packet::VERB_MULTICAST_GATHER);
for (unsigned int k = 0; k < numExplicitGatherPeers; ++k) {
const CertificateOfMembership* com = (network) ? ((network->config().com) ? &(network->config().com) : (const CertificateOfMembership*)0) : (const CertificateOfMembership*)0;
Packet outp(explicitGatherPeers[k], RR->identity.address(), Packet::VERB_MULTICAST_GATHER);
outp.append(network->id());
outp.append((uint8_t)((com) ? 0x01 : 0x00));
mg.mac().appendTo(outp);
@ -334,26 +326,15 @@ void Multicaster::send(
com->serialize(outp);
}
RR->node->expectReplyTo(outp.packetId());
RR->sw->send(tPtr,outp,true);
RR->sw->send(tPtr, outp, true);
Metrics::pkt_multicast_gather_out++;
}
}
gs.txQueue.push_back(OutboundMulticast());
OutboundMulticast &out = gs.txQueue.back();
OutboundMulticast& out = gs.txQueue.back();
out.init(
RR,
now,
network->id(),
network->config().disableCompression(),
limit,
gatherLimit,
src,
mg,
etherType,
data,
len);
out.init(RR, now, network->id(), network->config().disableCompression(), limit, gatherLimit, src, mg, etherType, data, len);
if (origin) {
out.logAsSent(origin);
@ -361,9 +342,9 @@ void Multicaster::send(
unsigned int count = 0;
for(unsigned int i=0;i<activeBridgeCount;++i) {
for (unsigned int i = 0; i < activeBridgeCount; ++i) {
if (activeBridges[i] != RR->identity.address()) {
out.sendAndLog(RR,tPtr,activeBridges[i]);
out.sendAndLog(RR, tPtr, activeBridges[i]);
if (++count >= limit) {
break;
}
@ -371,33 +352,36 @@ void Multicaster::send(
}
unsigned long idx = 0;
while ((count < limit)&&(idx < gs.members.size())) {
while ((count < limit) && (idx < gs.members.size())) {
Address ma(gs.members[indexes[idx++]].address);
if (std::find(activeBridges,activeBridges + activeBridgeCount,ma) == (activeBridges + activeBridgeCount)) {
out.sendAndLog(RR,tPtr,ma);
if (std::find(activeBridges, activeBridges + activeBridgeCount, ma) == (activeBridges + activeBridgeCount)) {
out.sendAndLog(RR, tPtr, ma);
++count;
}
}
}
} catch ( ... ) {} // this is a sanity check to catch any failures and make sure indexes[] still gets deleted
}
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;
delete[] indexes;
}
}
void Multicaster::clean(int64_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())) {
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 {
}
else {
++tx;
}
}
@ -418,15 +402,17 @@ void Multicaster::clean(int64_t now)
if (count) {
s->members.resize(count);
} else if (s->txQueue.empty()) {
}
else if (s->txQueue.empty()) {
_groups.erase(*k);
} else {
}
else {
s->members.clear();
}
}
}
void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member)
void Multicaster::_add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, MulticastGroupStatus& gs, const Address& member)
{
// assumes _groups_m is locked
@ -435,29 +421,32 @@ void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup
return;
}
std::vector<MulticastGroupMember>::iterator m(std::lower_bound(gs.members.begin(),gs.members.end(),member));
std::vector<MulticastGroupMember>::iterator m(std::lower_bound(gs.members.begin(), gs.members.end(), member));
if (m != gs.members.end()) {
if (m->address == member) {
m->timestamp = now;
return;
}
gs.members.insert(m,MulticastGroupMember(member,now));
} else {
gs.members.push_back(MulticastGroupMember(member,now));
gs.members.insert(m, MulticastGroupMember(member, now));
}
else {
gs.members.push_back(MulticastGroupMember(member, now));
}
for(std::list<OutboundMulticast>::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) {
for (std::list<OutboundMulticast>::iterator tx(gs.txQueue.begin()); tx != gs.txQueue.end();) {
if (tx->atLimit()) {
gs.txQueue.erase(tx++);
} else {
tx->sendIfNew(RR,tPtr,member);
}
else {
tx->sendIfNew(RR, tPtr, member);
if (tx->atLimit()) {
gs.txQueue.erase(tx++);
} else {
}
else {
++tx;
}
}
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,22 +14,21 @@
#ifndef ZT_MULTICASTER_HPP
#define ZT_MULTICASTER_HPP
#include <stdint.h>
#include <string.h>
#include <map>
#include <vector>
#include <list>
#include "Address.hpp"
#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 "OutboundMulticast.hpp"
#include "SharedPtr.hpp"
#include "Utils.hpp"
#include <list>
#include <map>
#include <stdint.h>
#include <string.h>
#include <vector>
namespace ZeroTier {
@ -41,10 +40,9 @@ class Network;
/**
* Database of known multicast peers within a network
*/
class Multicaster
{
public:
Multicaster(const RuntimeEnvironment *renv);
class Multicaster {
public:
Multicaster(const RuntimeEnvironment* renv);
~Multicaster();
/**
@ -55,10 +53,10 @@ public:
* @param mg Multicast group
* @param member New member address
*/
inline void add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member)
inline void add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, const Address& member)
{
Mutex::Lock _l(_groups_m);
_add(tPtr,now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member);
_add(tPtr, now, nwid, mg, _groups[Multicaster::Key(nwid, mg)], member);
}
/**
@ -74,7 +72,7 @@ public:
* @param count Number of addresses
* @param totalKnown Total number of known addresses as reported by peer
*/
void addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown);
void addMultiple(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, const void* addresses, unsigned int count, unsigned int totalKnown);
/**
* Remove a multicast group member (if present)
@ -83,7 +81,7 @@ public:
* @param mg Multicast group
* @param member Member to unsubscribe
*/
void remove(uint64_t nwid,const MulticastGroup &mg,const Address &member);
void remove(uint64_t nwid, const MulticastGroup& mg, const Address& member);
/**
* Append gather results to a packet by choosing registered multicast recipients at random
@ -103,7 +101,7 @@ public:
* @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;
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
@ -111,7 +109,7 @@ public:
* @param nwid Network ID
* @param mg Multicast group
*/
std::vector<Address> getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const;
std::vector<Address> getMembers(uint64_t nwid, const MulticastGroup& mg, unsigned int limit) const;
/**
* Send a multicast
@ -126,16 +124,7 @@ public:
* @param data Packet data
* @param len Length of packet data
*/
void send(
void *tPtr,
int64_t now,
const SharedPtr<Network> &network,
const Address &origin,
const MulticastGroup &mg,
const MAC &src,
unsigned int etherType,
const void *data,
unsigned int len);
void send(void* tPtr, int64_t now, const SharedPtr<Network>& network, const Address& origin, const MulticastGroup& mg, const MAC& src, unsigned int etherType, const void* data, unsigned int len);
/**
* Clean database
@ -145,53 +134,87 @@ public:
*/
void clean(int64_t now);
private:
struct Key
{
Key() : nwid(0),mg() {}
Key(uint64_t n,const MulticastGroup &g) : nwid(n),mg(g) {}
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 { return ((nwid == k.nwid)&&(mg == k.mg)); }
inline bool operator!=(const Key &k) const { return ((nwid != k.nwid)||(mg != k.mg)); }
inline unsigned long hashCode() const { return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32))); }
inline bool operator==(const Key& k) const
{
return ((nwid == k.nwid) && (mg == k.mg));
}
inline bool operator!=(const Key& k) const
{
return ((nwid != k.nwid) || (mg != k.mg));
}
inline unsigned long hashCode() const
{
return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32)));
}
};
struct MulticastGroupMember
{
MulticastGroupMember() {}
MulticastGroupMember(const Address &a,uint64_t ts) : address(a),timestamp(ts) {}
struct MulticastGroupMember {
MulticastGroupMember()
{
}
MulticastGroupMember(const Address& a, uint64_t ts) : address(a), timestamp(ts)
{
}
inline bool operator<(const MulticastGroupMember &a) const { return (address < a.address); }
inline bool operator==(const MulticastGroupMember &a) const { return (address == a.address); }
inline bool operator!=(const MulticastGroupMember &a) const { return (address != a.address); }
inline bool operator<(const Address &a) const { return (address < a); }
inline bool operator==(const Address &a) const { return (address == a); }
inline bool operator!=(const Address &a) const { return (address != a); }
inline bool operator<(const MulticastGroupMember& a) const
{
return (address < a.address);
}
inline bool operator==(const MulticastGroupMember& a) const
{
return (address == a.address);
}
inline bool operator!=(const MulticastGroupMember& a) const
{
return (address != a.address);
}
inline bool operator<(const Address& a) const
{
return (address < a);
}
inline bool operator==(const Address& a) const
{
return (address == a);
}
inline bool operator!=(const Address& a) const
{
return (address != a);
}
Address address;
int64_t timestamp; // time of last notification
int64_t timestamp; // time of last notification
};
struct MulticastGroupStatus
{
MulticastGroupStatus() : lastExplicitGather(0) {}
struct MulticastGroupStatus {
MulticastGroupStatus() : lastExplicitGather(0)
{
}
int64_t lastExplicitGather;
std::list<OutboundMulticast> txQueue; // pending outbound multicasts
std::vector<MulticastGroupMember> members; // members of this group
std::list<OutboundMulticast> txQueue; // pending outbound multicasts
std::vector<MulticastGroupMember> members; // members of this group
};
void _add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member);
void _add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, MulticastGroupStatus& gs, const Address& member);
const RuntimeEnvironment *const RR;
const RuntimeEnvironment* const RR;
Hashtable<Multicaster::Key,MulticastGroupStatus> _groups;
Hashtable<Multicaster::Key, MulticastGroupStatus> _groups;
Mutex _groups_m;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -18,19 +18,18 @@
#ifdef __UNIX_LIKE__
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
namespace ZeroTier {
// libpthread based mutex lock
class Mutex
{
public:
class Mutex {
public:
Mutex()
{
pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0);
pthread_mutex_init(&_mh, (const pthread_mutexattr_t*)0);
}
~Mutex()
@ -40,25 +39,22 @@ public:
inline void lock() const
{
pthread_mutex_lock(&((const_cast <Mutex *> (this))->_mh));
pthread_mutex_lock(&((const_cast<Mutex*>(this))->_mh));
}
inline void unlock() const
{
pthread_mutex_unlock(&((const_cast <Mutex *> (this))->_mh));
pthread_mutex_unlock(&((const_cast<Mutex*>(this))->_mh));
}
class Lock
{
public:
Lock(Mutex &m) :
_m(&m)
class Lock {
public:
Lock(Mutex& m) : _m(&m)
{
m.lock();
}
Lock(const Mutex &m) :
_m(const_cast<Mutex *>(&m))
Lock(const Mutex& m) : _m(const_cast<Mutex*>(&m))
{
_m->lock();
}
@ -68,18 +64,23 @@ public:
_m->unlock();
}
private:
Mutex *const _m;
private:
Mutex* const _m;
};
private:
Mutex(const Mutex &) {}
const Mutex &operator=(const Mutex &) { return *this; }
private:
Mutex(const Mutex&)
{
}
const Mutex& operator=(const Mutex&)
{
return *this;
}
pthread_mutex_t _mh;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif
@ -91,9 +92,8 @@ private:
namespace ZeroTier {
// Windows critical section based lock
class Mutex
{
public:
class Mutex {
public:
Mutex()
{
InitializeCriticalSection(&_cs);
@ -116,25 +116,22 @@ public:
inline void lock() const
{
(const_cast <Mutex *> (this))->lock();
(const_cast<Mutex*>(this))->lock();
}
inline void unlock() const
{
(const_cast <Mutex *> (this))->unlock();
(const_cast<Mutex*>(this))->unlock();
}
class Lock
{
public:
Lock(Mutex &m) :
_m(&m)
class Lock {
public:
Lock(Mutex& m) : _m(&m)
{
m.lock();
}
Lock(const Mutex &m) :
_m(const_cast<Mutex *>(&m))
Lock(const Mutex& m) : _m(const_cast<Mutex*>(&m))
{
_m->lock();
}
@ -144,19 +141,24 @@ public:
_m->unlock();
}
private:
Mutex *const _m;
private:
Mutex* const _m;
};
private:
Mutex(const Mutex &) {}
const Mutex &operator=(const Mutex &) { return *this; }
private:
Mutex(const Mutex&)
{
}
const Mutex& operator=(const Mutex&)
{
return *this;
}
CRITICAL_SECTION _cs;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif // _WIN32
#endif // _WIN32
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,33 +14,31 @@
#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 "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 "Membership.hpp"
#include "NetworkConfig.hpp"
#include "CertificateOfMembership.hpp"
#include "Constants.hpp"
#include "Dictionary.hpp"
#include "Hashtable.hpp"
#include "MAC.hpp"
#include "Membership.hpp"
#include "Metrics.hpp"
#include "MulticastGroup.hpp"
#include "Multicaster.hpp"
#include "Mutex.hpp"
#include "NetworkConfig.hpp"
#include "SharedPtr.hpp"
#include <algorithm>
#include <map>
#include <stdexcept>
#include <stdint.h>
#include <string>
#include <vector>
#define ZT_NETWORK_MAX_INCOMING_UPDATES 3
#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1)
#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1)
namespace ZeroTier {
@ -50,11 +48,10 @@ class Peer;
/**
* A virtual LAN
*/
class Network
{
class Network {
friend class SharedPtr<Network>;
public:
public:
/**
* Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0
*/
@ -63,7 +60,10 @@ public:
/**
* Compute primary controller device ID from network ID
*/
static inline Address controllerFor(uint64_t nwid) { return Address(nwid >> 24); }
static inline Address controllerFor(uint64_t nwid)
{
return Address(nwid >> 24);
}
/**
* Construct a new network
@ -77,18 +77,43 @@ public:
* @param uptr Arbitrary pointer used by externally-facing API (for user use)
* @param nconf Network config, if known
*/
Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr,const NetworkConfig *nconf);
Network(const RuntimeEnvironment* renv, void* tPtr, uint64_t nwid, void* uptr, const NetworkConfig* nconf);
~Network();
inline uint64_t id() const { return _id; }
inline Address controller() const { return Address(_id >> 24); }
inline bool multicastEnabled() const { return (_config.multicastLimit > 0); }
inline bool hasConfig() const { return (_config); }
inline uint64_t lastConfigUpdate() const { return _lastConfigUpdate; }
inline ZT_VirtualNetworkStatus status() const { Mutex::Lock _l(_lock); return _status(); }
inline const NetworkConfig &config() const { return _config; }
inline const MAC &mac() const { return _mac; }
inline uint64_t id() const
{
return _id;
}
inline Address controller() const
{
return Address(_id >> 24);
}
inline bool multicastEnabled() const
{
return (_config.multicastLimit > 0);
}
inline bool hasConfig() const
{
return (_config);
}
inline uint64_t lastConfigUpdate() const
{
return _lastConfigUpdate;
}
inline ZT_VirtualNetworkStatus status() const
{
Mutex::Lock _l(_lock);
return _status();
}
inline const NetworkConfig& config() const
{
return _config;
}
inline const MAC& mac() const
{
return _mac;
}
/**
* Apply filters to an outgoing packet
@ -111,17 +136,17 @@ public:
* @return True if packet should be sent, false if dropped or redirected
*/
bool filterOutgoingPacket(
void *tPtr,
void* tPtr,
const bool noTee,
const Address &ztSource,
const Address &ztDest,
const MAC &macSource,
const MAC &macDest,
const uint8_t *frameData,
const Address& ztSource,
const Address& ztDest,
const MAC& macSource,
const MAC& macDest,
const uint8_t* frameData,
const unsigned int frameLen,
const unsigned int etherType,
const unsigned int vlanId,
uint8_t &qosBucket);
uint8_t& qosBucket);
/**
* Apply filters to an incoming packet
@ -143,12 +168,12 @@ public:
* @return 0 == drop, 1 == accept, 2 == accept even if bridged
*/
int filterIncomingPacket(
void *tPtr,
const SharedPtr<Peer> &sourcePeer,
const Address &ztDest,
const MAC &macSource,
const MAC &macDest,
const uint8_t *frameData,
void* tPtr,
const SharedPtr<Peer>& sourcePeer,
const Address& ztDest,
const MAC& macSource,
const MAC& macDest,
const uint8_t* frameData,
const unsigned int frameLen,
const unsigned int etherType,
const unsigned int vlanId);
@ -160,7 +185,7 @@ public:
* @param includeBridgedGroups If true, also check groups we've learned via bridging
* @return True if this network endpoint / peer is a member
*/
bool subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const;
bool subscribedToMulticastGroup(const MulticastGroup& mg, bool includeBridgedGroups) const;
/**
* Subscribe to a multicast group
@ -168,14 +193,14 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param mg New multicast group
*/
void multicastSubscribe(void *tPtr,const MulticastGroup &mg);
void multicastSubscribe(void* tPtr, const MulticastGroup& mg);
/**
* Unsubscribe from a multicast group
*
* @param mg Multicast group
*/
void multicastUnsubscribe(const MulticastGroup &mg);
void multicastUnsubscribe(const MulticastGroup& mg);
/**
* Handle an inbound network config chunk
@ -191,7 +216,7 @@ public:
* @param ptr Index of chunk and related fields in packet
* @return Update ID if update was fully assembled and accepted or 0 otherwise
*/
uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr);
uint64_t handleConfigChunk(void* tPtr, const uint64_t packetId, const Address& source, const Buffer<ZT_PROTO_MAX_PACKET_LENGTH>& chunk, unsigned int ptr);
/**
* Set network configuration
@ -201,12 +226,12 @@ public:
* @param saveToDisk Save to disk? Used during loading, should usually be true otherwise.
* @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new
*/
int setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk);
int setConfiguration(void* tPtr, const NetworkConfig& nconf, bool saveToDisk);
/**
* Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this
*/
inline void setAccessDenied(void *tPtr)
inline void setAccessDenied(void* tPtr)
{
Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_ACCESS_DENIED;
@ -217,7 +242,7 @@ public:
/**
* Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this
*/
inline void setNotFound(void *tPtr)
inline void setNotFound(void* tPtr)
{
Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_NOT_FOUND;
@ -228,7 +253,7 @@ public:
/**
* Set netconf failure to 'authentication required' possibly with an authorization URL
*/
inline void setAuthenticationRequired(void *tPtr, const char *url)
inline void setAuthenticationRequired(void* tPtr, const char* url)
{
Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED;
@ -242,14 +267,14 @@ public:
* set netconf failure to 'authentication required' along with info needed
* for sso full flow authentication.
*/
void setAuthenticationRequired(void *tPtr, const char* issuerURL, const char* centralEndpoint, const char* clientID, const char *ssoProvider, const char* nonce, const char* state);
void setAuthenticationRequired(void* tPtr, const char* issuerURL, const char* centralEndpoint, const char* clientID, const char* ssoProvider, const char* nonce, const char* state);
/**
* Causes this network to request an updated configuration from its master node now
*
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/
void requestConfiguration(void *tPtr);
void requestConfiguration(void* tPtr);
/**
* Determine whether this peer is permitted to communicate on this network
@ -257,7 +282,7 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param peer Peer to check
*/
bool gate(void *tPtr,const SharedPtr<Peer> &peer);
bool gate(void* tPtr, const SharedPtr<Peer>& peer);
/**
* Check whether a given peer has recently had an association with this network
@ -270,7 +295,7 @@ public:
* @param addr Peer address
* @return True if peer has recently associated
*/
bool recentlyAssociatedWith(const Address &addr);
bool recentlyAssociatedWith(const Address& addr);
/**
* Do periodic cleanup and housekeeping tasks
@ -282,10 +307,10 @@ public:
*
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/
inline void sendUpdatesToMembers(void *tPtr)
inline void sendUpdatesToMembers(void* tPtr)
{
Mutex::Lock _l(_lock);
_sendUpdatesToMembers(tPtr,(const MulticastGroup *)0);
_sendUpdatesToMembers(tPtr, (const MulticastGroup*)0);
}
/**
@ -294,17 +319,20 @@ public:
* @param mac MAC address
* @return ZeroTier address of bridge to this MAC
*/
inline Address findBridgeTo(const MAC &mac) const
inline Address findBridgeTo(const MAC& mac) const
{
Mutex::Lock _l(_lock);
const Address *const br = _remoteBridgeRoutes.get(mac);
const Address* const br = _remoteBridgeRoutes.get(mac);
return ((br) ? *br : Address());
}
/**
* @return True if QoS is in effect for this network
*/
inline bool qosEnabled() { return false; }
inline bool qosEnabled()
{
return false;
}
/**
* Set a bridge route
@ -312,7 +340,7 @@ public:
* @param mac MAC address of destination
* @param addr Bridge this MAC is reachable behind
*/
void learnBridgeRoute(const MAC &mac,const Address &addr);
void learnBridgeRoute(const MAC& mac, const Address& addr);
/**
* Learn a multicast group that is bridged to our tap device
@ -321,52 +349,52 @@ public:
* @param mg Multicast group
* @param now Current time
*/
void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now);
void learnBridgedMulticastGroup(void* tPtr, const MulticastGroup& mg, int64_t now);
/**
* Validate a credential and learn it if it passes certificate and other checks
*/
Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com);
Membership::AddCredentialResult addCredential(void* tPtr, const CertificateOfMembership& com);
/**
* Validate a credential and learn it if it passes certificate and other checks
*/
inline Membership::AddCredentialResult addCredential(void *tPtr,const Capability &cap)
inline Membership::AddCredentialResult addCredential(void* tPtr, const Capability& cap)
{
if (cap.networkId() != _id) {
return Membership::ADD_REJECTED;
}
Mutex::Lock _l(_lock);
return _membership(cap.issuedTo()).addCredential(RR,tPtr,_config,cap);
return _membership(cap.issuedTo()).addCredential(RR, tPtr, _config, cap);
}
/**
* Validate a credential and learn it if it passes certificate and other checks
*/
inline Membership::AddCredentialResult addCredential(void *tPtr,const Tag &tag)
inline Membership::AddCredentialResult addCredential(void* tPtr, const Tag& tag)
{
if (tag.networkId() != _id) {
return Membership::ADD_REJECTED;
}
Mutex::Lock _l(_lock);
return _membership(tag.issuedTo()).addCredential(RR,tPtr,_config,tag);
return _membership(tag.issuedTo()).addCredential(RR, tPtr, _config, tag);
}
/**
* Validate a credential and learn it if it passes certificate and other checks
*/
Membership::AddCredentialResult addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev);
Membership::AddCredentialResult addCredential(void* tPtr, const Address& sentFrom, const Revocation& rev);
/**
* Validate a credential and learn it if it passes certificate and other checks
*/
inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfOwnership &coo)
inline Membership::AddCredentialResult addCredential(void* tPtr, const CertificateOfOwnership& coo)
{
if (coo.networkId() != _id) {
return Membership::ADD_REJECTED;
}
Mutex::Lock _l(_lock);
return _membership(coo.issuedTo()).addCredential(RR,tPtr,_config,coo);
return _membership(coo.issuedTo()).addCredential(RR, tPtr, _config, coo);
}
/**
@ -376,13 +404,13 @@ public:
* @param to Destination peer address
* @param now Current time
*/
inline void peerRequestedCredentials(void *tPtr,const Address &to,const int64_t now)
inline void peerRequestedCredentials(void* tPtr, const Address& to, const int64_t now)
{
Mutex::Lock _l(_lock);
Membership &m = _membership(to);
Membership& m = _membership(to);
const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT)) {
m.pushCredentials(RR,tPtr,now,to,_config);
if ((lastPushed < _lastConfigUpdate) || ((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT)) {
m.pushCredentials(RR, tPtr, now, to, _config);
}
}
@ -393,13 +421,13 @@ public:
* @param to Destination peer address
* @param now Current time
*/
inline void pushCredentialsIfNeeded(void *tPtr,const Address &to,const int64_t now)
inline void pushCredentialsIfNeeded(void* tPtr, const Address& to, const int64_t now)
{
Mutex::Lock _l(_lock);
Membership &m = _membership(to);
Membership& m = _membership(to);
const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT)) {
m.pushCredentials(RR,tPtr,now,to,_config);
if ((lastPushed < _lastConfigUpdate) || ((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT)) {
m.pushCredentials(RR, tPtr, now, to, _config);
}
}
@ -416,7 +444,7 @@ public:
*
* @param ec Buffer to fill with externally-visible network configuration
*/
inline void externalConfig(ZT_VirtualNetworkConfig *ec) const
inline void externalConfig(ZT_VirtualNetworkConfig* ec) const
{
Mutex::Lock _l(_lock);
_externalConfig(ec);
@ -425,36 +453,41 @@ public:
/**
* @return Externally usable pointer-to-pointer exported via the core API
*/
inline void **userPtr() { return &_uPtr; }
inline void** userPtr()
{
return &_uPtr;
}
private:
private:
ZT_VirtualNetworkStatus _status() const;
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
bool _gate(const SharedPtr<Peer> &peer);
void _sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup);
void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups);
void _externalConfig(ZT_VirtualNetworkConfig* ec) const; // assumes _lock is locked
bool _gate(const SharedPtr<Peer>& peer);
void _sendUpdatesToMembers(void* tPtr, const MulticastGroup* const newMulticastGroup);
void _announceMulticastGroupsTo(void* tPtr, const Address& peer, const std::vector<MulticastGroup>& allMulticastGroups);
std::vector<MulticastGroup> _allMulticastGroups() const;
Membership &_membership(const Address &a);
void _sendUpdateEvent(void *tPtr);
Membership& _membership(const Address& a);
void _sendUpdateEvent(void* tPtr);
const RuntimeEnvironment *const RR;
void *_uPtr;
const RuntimeEnvironment* const RR;
void* _uPtr;
const uint64_t _id;
std::string _nwidStr;
uint64_t _lastAnnouncedMulticastGroupsUpstream;
MAC _mac; // local MAC address
MAC _mac; // local MAC address
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)
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;
int64_t _lastConfigUpdate;
struct _IncomingConfigChunk
{
_IncomingConfigChunk() { memset(this,0,sizeof(_IncomingConfigChunk)); }
struct _IncomingConfigChunk {
_IncomingConfigChunk()
{
memset(this, 0, sizeof(_IncomingConfigChunk));
}
uint64_t ts;
uint64_t updateId;
uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS];
@ -466,17 +499,11 @@ private:
bool _destroyed;
enum {
NETCONF_FAILURE_NONE,
NETCONF_FAILURE_ACCESS_DENIED,
NETCONF_FAILURE_NOT_FOUND,
NETCONF_FAILURE_INIT_FAILED,
NETCONF_FAILURE_AUTHENTICATION_REQUIRED
} _netconfFailure;
int _portError; // return value from port config callback
enum { NETCONF_FAILURE_NONE, NETCONF_FAILURE_ACCESS_DENIED, NETCONF_FAILURE_NOT_FOUND, NETCONF_FAILURE_INIT_FAILED, NETCONF_FAILURE_AUTHENTICATION_REQUIRED } _netconfFailure;
int _portError; // return value from port config callback
std::string _authenticationURL;
Hashtable<Address,Membership> _memberships;
Hashtable<Address, Membership> _memberships;
Mutex _lock;

View file

@ -11,88 +11,87 @@
*/
/****/
#include <stdint.h>
#include "NetworkConfig.hpp"
#include <algorithm>
#include "NetworkConfig.hpp"
#include <stdint.h>
namespace ZeroTier {
bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const
bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d, bool includeLegacy) const
{
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> *tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
char tmp2[128] = {0};
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>* tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
char tmp2[128] = { 0 };
try {
d.clear();
// Try to put the more human-readable fields first
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION, (uint64_t)ZT_NETWORKCONFIG_VERSION)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID, this->networkId)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP, this->timestamp)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA, this->credentialTimeMaxDelta)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION, this->revision)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString(tmp2))) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO, this->issuedTo.toString(tmp2))) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget.toString(tmp2))) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET, this->remoteTraceTarget.toString(tmp2))) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL,(uint64_t)this->remoteTraceLevel)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL, (uint64_t)this->remoteTraceLevel)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS, this->flags)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT, (uint64_t)this->multicastLimit)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE, (uint64_t)this->type)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME, this->name)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU, (uint64_t)this->mtu)) {
delete tmp;
return false;
}
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
if (includeLegacy) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD,this->enableBroadcast())) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD, this->enableBroadcast())) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,this->isPrivate())) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD, this->isPrivate())) {
return false;
}
std::string v4s;
for(unsigned int i=0;i<staticIpCount;++i) {
for (unsigned int i = 0; i < staticIpCount; ++i) {
if (this->staticIps[i].ss_family == AF_INET) {
if (v4s.length() > 0) {
v4s.push_back(',');
@ -102,12 +101,12 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
}
}
if (v4s.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,v4s.c_str())) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD, v4s.c_str())) {
return false;
}
}
std::string v6s;
for(unsigned int i=0;i<staticIpCount;++i) {
for (unsigned int i = 0; i < staticIpCount; ++i) {
if (this->staticIps[i].ss_family == AF_INET6) {
if (v6s.length() > 0) {
v6s.push_back(',');
@ -117,7 +116,7 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
}
}
if (v6s.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,v6s.c_str())) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD, v6s.c_str())) {
return false;
}
}
@ -125,130 +124,131 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
std::string ets;
unsigned int et = 0;
ZT_VirtualNetworkRuleType lastrt = ZT_NETWORK_RULE_ACTION_ACCEPT;
for(unsigned int i=0;i<ruleCount;++i) {
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 (((int)lastrt < 32)||(lastrt == ZT_NETWORK_RULE_MATCH_ETHERTYPE)) {
}
else if (rt == ZT_NETWORK_RULE_ACTION_ACCEPT) {
if (((int)lastrt < 32) || (lastrt == ZT_NETWORK_RULE_MATCH_ETHERTYPE)) {
if (ets.length() > 0) {
ets.push_back(',');
}
char tmp2[16] = {0};
ets.append(Utils::hex((uint16_t)et,tmp2));
char tmp2[16] = { 0 };
ets.append(Utils::hex((uint16_t)et, tmp2));
}
et = 0;
}
lastrt = rt;
}
if (ets.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,ets.c_str())) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD, ets.c_str())) {
return false;
}
}
if (this->com) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,this->com.toString().c_str())) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD, this->com.toString().c_str())) {
return false;
}
}
std::string ab;
for(unsigned int i=0;i<this->specialistCount;++i) {
for (unsigned int i = 0; i < this->specialistCount; ++i) {
if ((this->specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
if (ab.length() > 0) {
ab.push_back(',');
}
char tmp2[16] = {0};
char tmp2[16] = { 0 };
ab.append(Address(this->specialists[i]).toString(tmp2));
}
}
if (ab.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,ab.c_str())) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD, ab.c_str())) {
return false;
}
}
}
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
// Then add binary blobs
if (this->com) {
tmp->clear();
this->com.serialize(*tmp);
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_COM, *tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->capabilityCount;++i) {
for (unsigned int i = 0; i < this->capabilityCount; ++i) {
this->capabilities[i].serialize(*tmp);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES, *tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->tagCount;++i) {
for (unsigned int i = 0; i < this->tagCount; ++i) {
this->tags[i].serialize(*tmp);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS, *tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->certificateOfOwnershipCount;++i) {
for (unsigned int i = 0; i < this->certificateOfOwnershipCount; ++i) {
this->certificatesOfOwnership[i].serialize(*tmp);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP, *tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->specialistCount;++i) {
for (unsigned int i = 0; i < this->specialistCount; ++i) {
tmp->append((uint64_t)this->specialists[i]);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS, *tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->routeCount;++i) {
reinterpret_cast<const InetAddress *>(&(this->routes[i].target))->serialize(*tmp);
reinterpret_cast<const InetAddress *>(&(this->routes[i].via))->serialize(*tmp);
for (unsigned int i = 0; i < this->routeCount; ++i) {
reinterpret_cast<const InetAddress*>(&(this->routes[i].target))->serialize(*tmp);
reinterpret_cast<const InetAddress*>(&(this->routes[i].via))->serialize(*tmp);
tmp->append((uint16_t)this->routes[i].flags);
tmp->append((uint16_t)this->routes[i].metric);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES, *tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->staticIpCount;++i) {
for (unsigned int i = 0; i < this->staticIpCount; ++i) {
this->staticIps[i].serialize(*tmp);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS, *tmp)) {
return false;
}
}
if (this->ruleCount) {
tmp->clear();
Capability::serializeRules(*tmp,rules,ruleCount);
Capability::serializeRules(*tmp, rules, ruleCount);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES, *tmp)) {
return false;
}
}
@ -257,59 +257,61 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
tmp->clear();
DNS::serializeDNS(*tmp, &dns);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS,*tmp)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS, *tmp)) {
return false;
}
}
if (this->ssoVersion == 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) {
return false;
}
if (this->ssoEnabled) {
if (this->authenticationURL[0]) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) {
return false;
}
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, this->authenticationExpiryTime)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, this->authenticationExpiryTime)) {
return false;
}
}
} else if(this->ssoVersion == 1) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) {
}
else if (this->ssoVersion == 1) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) {
return false;
}
//if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUER_URL, this->issuerURL)) {
// if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false;
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUER_URL, this->issuerURL)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider)) {
return false;
}
}
delete tmp;
} catch ( ... ) {
}
catch (...) {
delete tmp;
throw;
}
@ -317,83 +319,84 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
return true;
}
bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d)
bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d)
{
static const NetworkConfig NIL_NC;
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> *tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>* tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
try {
*this = NIL_NC;
// Fields that are always present, new or old
this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,0);
if (!this->networkId) {
this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID, 0);
if (! this->networkId) {
delete tmp;
return false;
}
this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,0);
this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,0);
this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0);
this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0);
if (!this->issuedTo) {
this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP, 0);
this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA, 0);
this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION, 0);
this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO, 0);
if (! this->issuedTo) {
delete tmp;
return false;
}
this->remoteTraceTarget = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET);
this->remoteTraceLevel = (Trace::Level)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL);
this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0);
d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name));
this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT, 0);
d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME, this->name, sizeof(this->name));
this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU,ZT_DEFAULT_MTU);
this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU, ZT_DEFAULT_MTU);
if (this->mtu < 1280) {
this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others
} else if (this->mtu > ZT_MAX_MTU) {
this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others
}
else if (this->mtu > ZT_MAX_MTU) {
this->mtu = ZT_MAX_MTU;
}
if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) {
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
char tmp2[1024] = {0};
if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION, 0) < 6) {
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
char tmp2[1024] = { 0 };
// Decode legacy fields if version is old
if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD)) {
this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST;
}
this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; // always enable for old-style netconf
this->type = (d.getB(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,true)) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC;
this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; // always enable for old-style netconf
this->type = (d.getB(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD, true)) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC;
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,tmp2,sizeof(tmp2)) > 0) {
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD, tmp2, sizeof(tmp2)) > 0) {
char* saveptr = (char*)0;
for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) {
if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
break;
}
InetAddress ip(f);
if (!ip.isNetwork()) {
if (! ip.isNetwork()) {
this->staticIps[this->staticIpCount++] = ip;
}
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,tmp2,sizeof(tmp2)) > 0) {
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD, tmp2, sizeof(tmp2)) > 0) {
char* saveptr = (char*)0;
for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) {
if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
break;
}
InetAddress ip(f);
if (!ip.isNetwork()) {
if (! ip.isNetwork()) {
this->staticIps[this->staticIpCount++] = ip;
}
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,tmp2,sizeof(tmp2)) > 0) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD, tmp2, sizeof(tmp2)) > 0) {
this->com.fromString(tmp2);
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,tmp2,sizeof(tmp2)) > 0) {
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD, tmp2, sizeof(tmp2)) > 0) {
char* saveptr = (char*)0;
for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) {
unsigned int et = Utils::hexStrToUInt(f) & 0xffff;
if ((this->ruleCount + 2) > ZT_MAX_NETWORK_RULES) {
break;
@ -405,67 +408,74 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
}
this->rules[this->ruleCount++].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
}
} else {
}
else {
this->rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT;
this->ruleCount = 1;
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,tmp2,sizeof(tmp2)) > 0) {
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
this->addSpecialist(Address(Utils::hexStrToU64(f)),ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE);
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD, tmp2, sizeof(tmp2)) > 0) {
char* saveptr = (char*)0;
for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) {
this->addSpecialist(Address(Utils::hexStrToU64(f)), ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE);
}
}
#else
#else
delete tmp;
return false;
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
} else {
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
}
else {
// Otherwise we can use the new fields
this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,0);
this->type = (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)ZT_NETWORK_TYPE_PRIVATE);
this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS, 0);
this->type = (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE, (uint64_t)ZT_NETWORK_TYPE_PRIVATE);
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) {
this->com.deserialize(*tmp,0);
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM, *tmp)) {
this->com.deserialize(*tmp, 0);
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES, *tmp)) {
try {
unsigned int p = 0;
while (p < tmp->size()) {
Capability cap;
p += cap.deserialize(*tmp,p);
p += cap.deserialize(*tmp, p);
this->capabilities[this->capabilityCount++] = cap;
}
} catch ( ... ) {}
std::sort(&(this->capabilities[0]),&(this->capabilities[this->capabilityCount]));
}
catch (...) {
}
std::sort(&(this->capabilities[0]), &(this->capabilities[this->capabilityCount]));
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_TAGS, *tmp)) {
try {
unsigned int p = 0;
while (p < tmp->size()) {
Tag tag;
p += tag.deserialize(*tmp,p);
p += tag.deserialize(*tmp, p);
this->tags[this->tagCount++] = tag;
}
} catch ( ... ) {}
std::sort(&(this->tags[0]),&(this->tags[this->tagCount]));
}
catch (...) {
}
std::sort(&(this->tags[0]), &(this->tags[this->tagCount]));
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP, *tmp)) {
unsigned int p = 0;
while (p < tmp->size()) {
if (certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP) {
p += certificatesOfOwnership[certificateOfOwnershipCount++].deserialize(*tmp,p);
} else {
p += certificatesOfOwnership[certificateOfOwnershipCount++].deserialize(*tmp, p);
}
else {
CertificateOfOwnership foo;
p += foo.deserialize(*tmp,p);
p += foo.deserialize(*tmp, p);
}
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS, *tmp)) {
unsigned int p = 0;
while ((p + 8) <= tmp->size()) {
if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) {
@ -475,11 +485,11 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ROUTES, *tmp)) {
unsigned int p = 0;
while ((p < tmp->size())&&(routeCount < ZT_MAX_NETWORK_ROUTES)) {
p += reinterpret_cast<InetAddress *>(&(this->routes[this->routeCount].target))->deserialize(*tmp,p);
p += reinterpret_cast<InetAddress *>(&(this->routes[this->routeCount].via))->deserialize(*tmp,p);
while ((p < tmp->size()) && (routeCount < ZT_MAX_NETWORK_ROUTES)) {
p += reinterpret_cast<InetAddress*>(&(this->routes[this->routeCount].target))->deserialize(*tmp, p);
p += reinterpret_cast<InetAddress*>(&(this->routes[this->routeCount].via))->deserialize(*tmp, p);
this->routes[this->routeCount].flags = tmp->at<uint16_t>(p);
p += 2;
this->routes[this->routeCount].metric = tmp->at<uint16_t>(p);
@ -488,17 +498,17 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS, *tmp)) {
unsigned int p = 0;
while ((p < tmp->size())&&(staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
p += this->staticIps[this->staticIpCount++].deserialize(*tmp,p);
while ((p < tmp->size()) && (staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
p += this->staticIps[this->staticIpCount++].deserialize(*tmp, p);
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_RULES, *tmp)) {
this->ruleCount = 0;
unsigned int p = 0;
Capability::deserializeRules(*tmp,p,this->rules,this->ruleCount,ZT_MAX_NETWORK_RULES);
Capability::deserializeRules(*tmp, p, this->rules, this->ruleCount, ZT_MAX_NETWORK_RULES);
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_DNS, *tmp)) {
@ -513,16 +523,19 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
// implicit flow
if (this->ssoEnabled) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) {
this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; // ensure null terminated
} else {
this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; // ensure null terminated
}
else {
this->authenticationURL[0] = 0;
}
this->authenticationExpiryTime = d.getI(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, 0);
} else {
}
else {
this->authenticationURL[0] = 0;
this->authenticationExpiryTime = 0;
}
} else if (this->ssoVersion == 1) {
}
else if (this->ssoVersion == 1) {
// full flow
if (this->ssoEnabled) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) {
@ -545,11 +558,13 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider, (unsigned int)(sizeof(this->ssoProvider))) > 0) {
this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0;
} else {
}
else {
strncpy(this->ssoProvider, "default", sizeof(this->ssoProvider));
this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0;
}
} else {
}
else {
this->authenticationURL[0] = 0;
this->authenticationExpiryTime = 0;
this->centralAuthURL[0] = 0;
@ -562,16 +577,17 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
}
}
//printf("~~~\n%s\n~~~\n",d.data());
//dump();
//printf("~~~\n");
// printf("~~~\n%s\n~~~\n",d.data());
// dump();
// printf("~~~\n");
delete tmp;
return true;
} catch ( ... ) {
}
catch (...) {
delete tmp;
return false;
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,31 +14,29 @@
#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 "DNS.hpp"
#include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#include "Address.hpp"
#include "Buffer.hpp"
#include "Capability.hpp"
#include "CertificateOfMembership.hpp"
#include "CertificateOfOwnership.hpp"
#include "Capability.hpp"
#include "Tag.hpp"
#include "Constants.hpp"
#include "DNS.hpp"
#include "Dictionary.hpp"
#include "Hashtable.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#include "Tag.hpp"
#include "Trace.hpp"
#include "Utils.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
/**
* Default time delta for COMs, tags, and capabilities
@ -93,7 +91,9 @@
namespace ZeroTier {
// Dictionary capacity needed for max size network config
#define ZT_NETWORKCONFIG_DICT_CAPACITY (4096 + (sizeof(ZT_VirtualNetworkConfig)) + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) + (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP))
#define ZT_NETWORKCONFIG_DICT_CAPACITY \
(4096 + (sizeof(ZT_VirtualNetworkConfig)) + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) \
+ (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP))
// Dictionary capacity needed for max size network meta-data
#define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 1024
@ -248,46 +248,45 @@ namespace ZeroTier {
* This is a memcpy()'able structure and is safe (in a crash sense) to modify
* without locks.
*/
class NetworkConfig
{
public:
NetworkConfig() :
networkId(0),
timestamp(0),
credentialTimeMaxDelta(0),
revision(0),
issuedTo(),
remoteTraceTarget(),
flags(0),
remoteTraceLevel(Trace::LEVEL_NORMAL),
mtu(0),
multicastLimit(0),
specialistCount(0),
routeCount(0),
staticIpCount(0),
ruleCount(0),
capabilityCount(0),
tagCount(0),
certificateOfOwnershipCount(0),
capabilities(),
tags(),
certificatesOfOwnership(),
type(ZT_NETWORK_TYPE_PRIVATE),
dnsCount(0),
ssoEnabled(false),
authenticationURL(),
authenticationExpiryTime(0),
issuerURL(),
centralAuthURL(),
ssoNonce(),
ssoState(),
ssoClientID()
class NetworkConfig {
public:
NetworkConfig()
: networkId(0)
, timestamp(0)
, credentialTimeMaxDelta(0)
, revision(0)
, issuedTo()
, remoteTraceTarget()
, flags(0)
, remoteTraceLevel(Trace::LEVEL_NORMAL)
, mtu(0)
, multicastLimit(0)
, specialistCount(0)
, routeCount(0)
, staticIpCount(0)
, ruleCount(0)
, capabilityCount(0)
, tagCount(0)
, certificateOfOwnershipCount(0)
, capabilities()
, tags()
, certificatesOfOwnership()
, type(ZT_NETWORK_TYPE_PRIVATE)
, dnsCount(0)
, ssoEnabled(false)
, authenticationURL()
, authenticationExpiryTime(0)
, issuerURL()
, centralAuthURL()
, ssoNonce()
, ssoState()
, ssoClientID()
{
name[0] = 0;
memset(specialists, 0, sizeof(uint64_t)*ZT_MAX_NETWORK_SPECIALISTS);
memset(routes, 0, sizeof(ZT_VirtualNetworkRoute)*ZT_MAX_NETWORK_ROUTES);
memset(staticIps, 0, sizeof(InetAddress)*ZT_MAX_ZT_ASSIGNED_ADDRESSES);
memset(rules, 0, sizeof(ZT_VirtualNetworkRule)*ZT_MAX_NETWORK_RULES);
memset(specialists, 0, sizeof(uint64_t) * ZT_MAX_NETWORK_SPECIALISTS);
memset(routes, 0, sizeof(ZT_VirtualNetworkRoute) * ZT_MAX_NETWORK_ROUTES);
memset(staticIps, 0, sizeof(InetAddress) * ZT_MAX_ZT_ASSIGNED_ADDRESSES);
memset(rules, 0, sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES);
memset(&dns, 0, sizeof(ZT_VirtualNetworkDNS));
memset(authenticationURL, 0, sizeof(authenticationURL));
memset(issuerURL, 0, sizeof(issuerURL));
@ -305,7 +304,7 @@ public:
* @param includeLegacy If true, include legacy fields for old node versions
* @return True if dictionary was successfully created, false if e.g. overflow
*/
bool toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const;
bool toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d, bool includeLegacy) const;
/**
* Read this network config from a dictionary
@ -313,17 +312,23 @@ public:
* @param d Dictionary (non-const since it might be modified during parse, should not be used after call)
* @return True if dictionary was valid and network config successfully initialized
*/
bool fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d);
bool fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d);
/**
* @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network
*/
inline bool enableBroadcast() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); }
inline bool enableBroadcast() const
{
return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0);
}
/**
* @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns
*/
inline bool ndpEmulation() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); }
inline bool ndpEmulation() const
{
return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0);
}
/**
* @return True if frames should not be compressed
@ -344,12 +349,18 @@ public:
/**
* @return Network type is public (no access control)
*/
inline bool isPublic() const { return (this->type == ZT_NETWORK_TYPE_PUBLIC); }
inline bool isPublic() const
{
return (this->type == ZT_NETWORK_TYPE_PUBLIC);
}
/**
* @return Network type is private (certificate access control)
*/
inline bool isPrivate() const { return (this->type == ZT_NETWORK_TYPE_PRIVATE); }
inline bool isPrivate() const
{
return (this->type == ZT_NETWORK_TYPE_PRIVATE);
}
/**
* @return ZeroTier addresses of devices on this network designated as active bridges
@ -357,7 +368,7 @@ public:
inline std::vector<Address> activeBridges() const
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
r.push_back(Address(specialists[i]));
}
@ -368,7 +379,7 @@ public:
inline unsigned int activeBridges(Address ab[ZT_MAX_NETWORK_SPECIALISTS]) const
{
unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
ab[c++] = specialists[i];
}
@ -376,10 +387,10 @@ public:
return c;
}
inline bool isActiveBridge(const Address &a) const
inline bool isActiveBridge(const Address& a) const
{
for(unsigned int i=0;i<specialistCount;++i) {
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)&&(a == specialists[i])) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) && (a == specialists[i])) {
return true;
}
}
@ -389,7 +400,7 @@ public:
inline std::vector<Address> anchors() const
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0) {
r.push_back(Address(specialists[i]));
}
@ -400,7 +411,7 @@ public:
inline std::vector<Address> multicastReplicators() const
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) {
r.push_back(Address(specialists[i]));
}
@ -411,7 +422,7 @@ public:
inline unsigned int multicastReplicators(Address mr[ZT_MAX_NETWORK_SPECIALISTS]) const
{
unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) {
mr[c++] = specialists[i];
}
@ -419,10 +430,10 @@ public:
return c;
}
inline bool isMulticastReplicator(const Address &a) const
inline bool isMulticastReplicator(const Address& a) const
{
for(unsigned int i=0;i<specialistCount;++i) {
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0)&&(a == specialists[i])) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) && (a == specialists[i])) {
return true;
}
}
@ -432,7 +443,7 @@ public:
inline std::vector<Address> alwaysContactAddresses() const
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
r.push_back(Address(specialists[i]));
}
@ -443,7 +454,7 @@ public:
inline unsigned int alwaysContactAddresses(Address ac[ZT_MAX_NETWORK_SPECIALISTS]) const
{
unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
ac[c++] = specialists[i];
}
@ -451,9 +462,9 @@ public:
return c;
}
inline void alwaysContactAddresses(Hashtable< Address,std::vector<InetAddress> > &a) const
inline void alwaysContactAddresses(Hashtable<Address, std::vector<InetAddress> >& a) const
{
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
a[Address(specialists[i])];
}
@ -464,19 +475,28 @@ public:
* @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
inline bool permitsBridging(const Address& fromPeer) const
{
for(unsigned int i=0;i<specialistCount;++i) {
if ((fromPeer == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)) {
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;
}
inline operator bool() const { 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)); }
inline operator bool() const
{
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));
}
/**
* Add a specialist or mask flags if already present
@ -488,10 +508,10 @@ public:
* @param f Flags (OR of specialist role/type flags)
* @return True if successfully masked or added
*/
inline bool addSpecialist(const Address &a,const uint64_t f)
inline bool addSpecialist(const Address& a, const uint64_t f)
{
const uint64_t aint = a.toInt();
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & 0xffffffffffULL) == aint) {
specialists[i] |= f;
return true;
@ -504,24 +524,24 @@ public:
return false;
}
const Capability *capability(const uint32_t id) const
const Capability* capability(const uint32_t id) const
{
for(unsigned int i=0;i<capabilityCount;++i) {
for (unsigned int i = 0; i < capabilityCount; ++i) {
if (capabilities[i].id() == id) {
return &(capabilities[i]);
}
}
return (Capability *)0;
return (Capability*)0;
}
const Tag *tag(const uint32_t id) const
const Tag* tag(const uint32_t id) const
{
for(unsigned int i=0;i<tagCount;++i) {
for (unsigned int i = 0; i < tagCount; ++i) {
if (tags[i].id() == id) {
return &(tags[i]);
}
}
return (Tag *)0;
return (Tag*)0;
}
/**
@ -729,6 +749,6 @@ public:
char ssoProvider[64];
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -14,13 +14,13 @@
#ifndef ZT_NETWORKCONFIGMASTER_HPP
#define ZT_NETWORKCONFIGMASTER_HPP
#include <stdint.h>
#include "Address.hpp"
#include "Constants.hpp"
#include "Dictionary.hpp"
#include "NetworkConfig.hpp"
#include "Revocation.hpp"
#include "Address.hpp"
#include <stdint.h>
namespace ZeroTier {
@ -30,24 +30,15 @@ struct InetAddress;
/**
* Interface for network controller implementations
*/
class NetworkController
{
public:
enum ErrorCode
{
NC_ERROR_NONE = 0,
NC_ERROR_OBJECT_NOT_FOUND = 1,
NC_ERROR_ACCESS_DENIED = 2,
NC_ERROR_INTERNAL_SERVER_ERROR = 3,
NC_ERROR_AUTHENTICATION_REQUIRED = 4
};
class NetworkController {
public:
enum ErrorCode { NC_ERROR_NONE = 0, NC_ERROR_OBJECT_NOT_FOUND = 1, NC_ERROR_ACCESS_DENIED = 2, NC_ERROR_INTERNAL_SERVER_ERROR = 3, NC_ERROR_AUTHENTICATION_REQUIRED = 4 };
/**
* Interface for sender used to send pushes and replies
*/
class Sender
{
public:
class Sender {
public:
/**
* Send a configuration to a remote peer
*
@ -57,7 +48,7 @@ public:
* @param nc Network configuration to send
* @param sendLegacyFormatConfig If true, send an old-format network config
*/
virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig) = 0;
virtual void ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address& destination, const NetworkConfig& nc, bool sendLegacyFormatConfig) = 0;
/**
* Send revocation to a node
@ -65,14 +56,14 @@ public:
* @param destination Destination node address
* @param rev Revocation to send
*/
virtual void ncSendRevocation(const Address &destination,const Revocation &rev) = 0;
virtual void ncSendRevocation(const Address& destination, const Revocation& rev) = 0;
/**
* Send a network configuration request error
*
* If errorData/errorDataSize are provided they must point to a valid serialized
* Dictionary containing error data. They can be null/zero if not specified.
*
*
* @param nwid Network ID
* @param requestPacketId Request packet ID or 0 if none
* @param destination Destination peer Address
@ -80,11 +71,15 @@ public:
* @param errorData Data associated with error or NULL if none
* @param errorDataSize Size of errorData in bytes
*/
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize) = 0;
virtual void ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address& destination, NetworkController::ErrorCode errorCode, const void* errorData, unsigned int errorDataSize) = 0;
};
NetworkController() {}
virtual ~NetworkController() {}
NetworkController()
{
}
virtual ~NetworkController()
{
}
/**
* Called when this is added to a Node to initialize and supply info
@ -92,7 +87,7 @@ public:
* @param signingId Identity for signing of network configurations, certs, etc.
* @param sender Sender implementation for sending replies or config pushes
*/
virtual void init(const Identity &signingId,Sender *sender) = 0;
virtual void init(const Identity& signingId, Sender* sender) = 0;
/**
* Handle a network configuration request
@ -104,14 +99,9 @@ public:
* @param metaData Meta-data bundled with request (if any)
* @return Returns NETCONF_QUERY_OK if result 'nc' is valid, or an error code on error
*/
virtual void request(
uint64_t nwid,
const InetAddress &fromAddr,
uint64_t requestPacketId,
const Identity &identity,
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData) = 0;
virtual void request(uint64_t nwid, const InetAddress& fromAddr, uint64_t requestPacketId, const Identity& identity, const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY>& metaData) = 0;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,29 +14,26 @@
#ifndef ZT_NODE_HPP
#define ZT_NODE_HPP
#include "../include/ZeroTierOne.h"
#include "Bond.hpp"
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include "Mutex.hpp"
#include "Network.hpp"
#include "NetworkController.hpp"
#include "Path.hpp"
#include "RuntimeEnvironment.hpp"
#include "Salsa20.hpp"
#include "SelfAwareness.hpp"
#include <map>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <map>
#include <vector>
#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"
#include "NetworkController.hpp"
#include "Hashtable.hpp"
#include "Bond.hpp"
#include "SelfAwareness.hpp"
// Bit mask for "expecting reply" hash
#define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255
#define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31
@ -50,94 +47,76 @@ class World;
*
* The pointer returned by ZT_Node_new() is an instance of this class.
*/
class Node : public NetworkController::Sender
{
public:
Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now);
class Node : public NetworkController::Sender {
public:
Node(void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now);
virtual ~Node();
// Get rid of alignment warnings on 32-bit Windows and possibly improve performance
#ifdef __WINDOWS__
void * operator new(size_t i) { return _mm_malloc(i,16); }
void operator delete(void* p) { _mm_free(p); }
void* operator new(size_t i)
{
return _mm_malloc(i, 16);
}
void operator delete(void* p)
{
_mm_free(p);
}
#endif
// Public API Functions ----------------------------------------------------
ZT_ResultCode processWirePacket(
void *tptr,
int64_t now,
int64_t localSocket,
const struct sockaddr_storage *remoteAddress,
const void *packetData,
unsigned int packetLength,
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processWirePacket(void* tptr, int64_t now, int64_t localSocket, const struct sockaddr_storage* remoteAddress, const void* packetData, unsigned int packetLength, volatile int64_t* nextBackgroundTaskDeadline);
ZT_ResultCode processVirtualNetworkFrame(
void *tptr,
void* tptr,
int64_t now,
uint64_t nwid,
uint64_t sourceMac,
uint64_t destMac,
unsigned int etherType,
unsigned int vlanId,
const void *frameData,
const void* frameData,
unsigned int frameLength,
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr);
ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr);
ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_ResultCode orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed);
ZT_ResultCode deorbit(void *tptr,uint64_t moonWorldId);
volatile int64_t* nextBackgroundTaskDeadline);
ZT_ResultCode processBackgroundTasks(void* tptr, int64_t now, volatile int64_t* nextBackgroundTaskDeadline);
ZT_ResultCode join(uint64_t nwid, void* uptr, void* tptr);
ZT_ResultCode leave(uint64_t nwid, void** uptr, void* tptr);
ZT_ResultCode multicastSubscribe(void* tptr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi);
ZT_ResultCode multicastUnsubscribe(uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi);
ZT_ResultCode orbit(void* tptr, uint64_t moonWorldId, uint64_t moonSeed);
ZT_ResultCode deorbit(void* tptr, uint64_t moonWorldId);
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 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();
int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len);
void setNetconfMaster(void *networkControllerInstance);
int sendUserMessage(void* tptr, uint64_t dest, uint64_t typeId, const void* data, unsigned int len);
void setNetconfMaster(void* networkControllerInstance);
// Internal functions ------------------------------------------------------
inline int64_t now() const { return _now; }
inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
inline int64_t now() const
{
return (_cb.wirePacketSendFunction(
reinterpret_cast<ZT_Node *>(this),
_uPtr,
tPtr,
localSocket,
reinterpret_cast<const struct sockaddr_storage *>(&addr),
data,
len,
ttl) == 0);
return _now;
}
inline void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
inline bool putPacket(void* tPtr, const int64_t localSocket, const InetAddress& addr, const void* data, unsigned int len, unsigned int ttl = 0)
{
_cb.virtualNetworkFrameFunction(
reinterpret_cast<ZT_Node *>(this),
_uPtr,
tPtr,
nwid,
nuptr,
source.toInt(),
dest.toInt(),
etherType,
vlanId,
data,
len);
return (_cb.wirePacketSendFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, localSocket, reinterpret_cast<const struct sockaddr_storage*>(&addr), data, len, ttl) == 0);
}
inline void putFrame(void* tPtr, uint64_t nwid, void** nuptr, const MAC& source, const MAC& dest, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len)
{
_cb.virtualNetworkFrameFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, nwid, nuptr, source.toInt(), dest.toInt(), etherType, vlanId, data, len);
}
inline SharedPtr<Network> network(uint64_t nwid) const
{
Mutex::Lock _l(_networks_m);
const SharedPtr<Network> *n = _networks.get(nwid);
const SharedPtr<Network>* n = _networks.get(nwid);
if (n) {
return *n;
}
@ -150,14 +129,14 @@ public:
return _networks.contains(nwid);
}
inline std::vector< SharedPtr<Network> > allNetworks() const
inline std::vector<SharedPtr<Network> > allNetworks() const
{
std::vector< SharedPtr<Network> > nw;
std::vector<SharedPtr<Network> > nw;
Mutex::Lock _l(_networks_m);
Hashtable< uint64_t,SharedPtr<Network> >::Iterator i(*const_cast< Hashtable< uint64_t,SharedPtr<Network> > * >(&_networks));
uint64_t *k = (uint64_t *)0;
SharedPtr<Network> *v = (SharedPtr<Network> *)0;
while (i.next(k,v)) {
Hashtable<uint64_t, SharedPtr<Network> >::Iterator i(*const_cast<Hashtable<uint64_t, SharedPtr<Network> >*>(&_networks));
uint64_t* k = (uint64_t*)0;
SharedPtr<Network>* v = (SharedPtr<Network>*)0;
while (i.next(k, v)) {
nw.push_back(*v);
}
return nw;
@ -169,30 +148,60 @@ public:
return _directPaths;
}
inline void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ev,md); }
inline void postEvent(void* tPtr, ZT_Event ev, const void* md = (const void*)0)
{
_cb.eventCallback(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, ev, md);
}
inline int configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,nwid,nuptr,op,nc); }
inline int configureVirtualNetworkPort(void* tPtr, uint64_t nwid, void** nuptr, ZT_VirtualNetworkConfigOperation op, const ZT_VirtualNetworkConfig* nc)
{
return _cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, nwid, nuptr, op, nc);
}
inline bool online() const { return _online; }
inline bool online() const
{
return _online;
}
inline int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,maxlen); }
inline void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,(int)len); }
inline void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2]) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,(const void *)0,-1); }
inline int stateObjectGet(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2], void* const data, const unsigned int maxlen)
{
return _cb.stateGetFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, type, id, data, maxlen);
}
inline void stateObjectPut(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2], const void* const data, const unsigned int len)
{
_cb.statePutFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, type, id, data, (int)len);
}
inline void stateObjectDelete(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2])
{
_cb.statePutFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, type, id, (const void*)0, -1);
}
bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress);
inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast<struct sockaddr_storage *>(&addr)) != 0) : false ); }
bool shouldUsePathForZeroTierTraffic(void* tPtr, const Address& ztaddr, const int64_t localSocket, const InetAddress& remoteAddress);
inline bool externalPathLookup(void* tPtr, const Address& ztaddr, int family, InetAddress& addr)
{
return ((_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, ztaddr.toInt(), family, reinterpret_cast<struct sockaddr_storage*>(&addr)) != 0) : false);
}
uint64_t prng();
ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage* pathNetwork, const ZT_PhysicalPathConfiguration* pathConfig);
World planet() const;
std::vector<World> moons() const;
inline const Identity &identity() const { return _RR.identity; }
inline const Identity& identity() const
{
return _RR.identity;
}
inline const std::vector<InetAddress> SurfaceAddresses() const { return _RR.sa->whoami(); }
inline const std::vector<InetAddress> SurfaceAddresses() const
{
return _RR.sa->whoami();
}
inline Bond *bondController() const { return _RR.bc; }
inline Bond* bondController() const
{
return _RR.bc;
}
/**
* Register that we are expecting a reply to a packet ID
@ -224,7 +233,7 @@ public:
{
const uint32_t pid2 = (uint32_t)(packetId >> 32);
const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1);
for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) {
for (unsigned long i = 0; i <= ZT_EXPECTING_REPLIES_BUCKET_MASK2; ++i) {
if (_expectingRepliesTo[bucket][i] == pid2) {
return true;
}
@ -239,7 +248,7 @@ public:
* @param from Source address of packet
* @return True if within rate limits
*/
inline bool rateGateIdentityVerification(const int64_t now,const InetAddress &from)
inline bool rateGateIdentityVerification(const int64_t now, const InetAddress& from)
{
unsigned long iph = from.rateGateHash();
if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) {
@ -249,17 +258,23 @@ public:
return false;
}
virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig);
virtual void ncSendRevocation(const Address &destination,const Revocation &rev);
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize);
virtual void ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address& destination, const NetworkConfig& nc, bool sendLegacyFormatConfig);
virtual void ncSendRevocation(const Address& destination, const Revocation& rev);
virtual void ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address& destination, NetworkController::ErrorCode errorCode, const void* errorData, unsigned int errorDataSize);
inline const Address &remoteTraceTarget() const { return _remoteTraceTarget; }
inline Trace::Level remoteTraceLevel() const { return _remoteTraceLevel; }
inline const Address& remoteTraceTarget() const
{
return _remoteTraceTarget;
}
inline Trace::Level remoteTraceLevel() const
{
return _remoteTraceLevel;
}
inline bool localControllerHasAuthorized(const int64_t now,const uint64_t nwid,const Address &addr) const
inline bool localControllerHasAuthorized(const int64_t now, const uint64_t nwid, const Address& addr) const
{
_localControllerAuthorizations_m.lock();
const int64_t *const at = _localControllerAuthorizations.get(_LocalControllerAuth(nwid,addr));
const int64_t* const at = _localControllerAuthorizations.get(_LocalControllerAuth(nwid, addr));
_localControllerAuthorizations_m.unlock();
if (at) {
return ((now - *at) < (ZT_NETWORK_AUTOCONF_DELAY * 3));
@ -267,7 +282,7 @@ public:
return false;
}
inline void statsLogVerb(const unsigned int v,const unsigned int bytes)
inline void statsLogVerb(const unsigned int v, const unsigned int bytes)
{
++_stats.inVerbCounts[v];
_stats.inVerbBytes[v] += (uint64_t)bytes;
@ -285,11 +300,10 @@ public:
void initMultithreading(unsigned int concurrency, bool cpuPinningEnabled);
public:
public:
RuntimeEnvironment _RR;
RuntimeEnvironment *RR;
void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P
RuntimeEnvironment* RR;
void* _uPtr; // _uptr (lower case) is reserved in Visual Studio :P
ZT_Node_Callbacks _cb;
// For tracking packet IDs to filter out OK/ERROR replies to packets we did not send
@ -304,18 +318,28 @@ public:
// Map that remembers if we have recently sent a network config to someone
// querying us as a controller.
struct _LocalControllerAuth
{
uint64_t nwid,address;
_LocalControllerAuth(const uint64_t nwid_,const Address &address_) : nwid(nwid_),address(address_.toInt()) {}
inline unsigned long hashCode() const { return (unsigned long)(nwid ^ address); }
inline bool operator==(const _LocalControllerAuth &a) const { return ((a.nwid == nwid)&&(a.address == address)); }
inline bool operator!=(const _LocalControllerAuth &a) const { return ((a.nwid != nwid)||(a.address != address)); }
struct _LocalControllerAuth {
uint64_t nwid, address;
_LocalControllerAuth(const uint64_t nwid_, const Address& address_) : nwid(nwid_), address(address_.toInt())
{
}
inline unsigned long hashCode() const
{
return (unsigned long)(nwid ^ address);
}
inline bool operator==(const _LocalControllerAuth& a) const
{
return ((a.nwid == nwid) && (a.address == address));
}
inline bool operator!=(const _LocalControllerAuth& a) const
{
return ((a.nwid != nwid) || (a.address != address));
}
};
Hashtable< _LocalControllerAuth,int64_t > _localControllerAuthorizations;
Hashtable<_LocalControllerAuth, int64_t> _localControllerAuthorizations;
Mutex _localControllerAuthorizations_m;
Hashtable< uint64_t,SharedPtr<Network> > _networks;
Hashtable<uint64_t, SharedPtr<Network> > _networks;
Mutex _networks_m;
std::vector<InetAddress> _directPaths;
@ -336,6 +360,6 @@ public:
bool _lowBandwidthMode;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,28 +11,29 @@
*/
/****/
#include "Constants.hpp"
#include "RuntimeEnvironment.hpp"
#include "OutboundMulticast.hpp"
#include "Switch.hpp"
#include "Constants.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier {
void OutboundMulticast::init(
const RuntimeEnvironment *RR,
const RuntimeEnvironment* RR,
uint64_t timestamp,
uint64_t nwid,
bool disableCompression,
unsigned int limit,
unsigned int gatherLimit,
const MAC &src,
const MulticastGroup &dest,
const MAC& src,
const MulticastGroup& dest,
unsigned int etherType,
const void *payload,
const void* payload,
unsigned int len)
{
uint8_t flags = 0;
@ -42,8 +43,9 @@ void OutboundMulticast::init(
if (src) {
_macSrc = src;
flags |= 0x04;
} else {
_macSrc.fromAddress(RR->identity.address(),nwid);
}
else {
_macSrc.fromAddress(RR->identity.address(), nwid);
}
_macDest = dest.mac();
_limit = limit;
@ -67,26 +69,26 @@ void OutboundMulticast::init(
dest.mac().appendTo(_packet);
_packet.append((uint32_t)dest.adi());
_packet.append((uint16_t)etherType);
_packet.append(payload,_frameLen);
if (!disableCompression) {
_packet.append(payload, _frameLen);
if (! disableCompression) {
_packet.compress();
}
memcpy(_frameData,payload,_frameLen);
memcpy(_frameData, payload, _frameLen);
}
void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr)
void OutboundMulticast::sendOnly(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr)
{
const SharedPtr<Network> nw(RR->node->network(_nwid));
uint8_t QoSBucket = 255; // Dummy value
if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr,_macSrc,_macDest,_frameData,_frameLen,_etherType,0,QoSBucket))) {
nw->pushCredentialsIfNeeded(tPtr,toAddr,RR->node->now());
uint8_t QoSBucket = 255; // Dummy value
if ((nw) && (nw->filterOutgoingPacket(tPtr, true, RR->identity.address(), toAddr, _macSrc, _macDest, _frameData, _frameLen, _etherType, 0, QoSBucket))) {
nw->pushCredentialsIfNeeded(tPtr, toAddr, RR->node->now());
_packet.newInitializationVector();
_packet.setDestination(toAddr);
RR->node->expectReplyTo(_packet.packetId());
_tmp = _packet;
RR->sw->send(tPtr,_tmp,true);
RR->sw->send(tPtr, _tmp, true);
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,17 +14,16 @@
#ifndef ZT_OUTBOUNDMULTICAST_HPP
#define ZT_OUTBOUNDMULTICAST_HPP
#include <stdint.h>
#include <vector>
#include <algorithm>
#include "Address.hpp"
#include "Constants.hpp"
#include "MAC.hpp"
#include "MulticastGroup.hpp"
#include "Address.hpp"
#include "Packet.hpp"
#include <algorithm>
#include <stdint.h>
#include <vector>
namespace ZeroTier {
class CertificateOfMembership;
@ -35,15 +34,16 @@ class RuntimeEnvironment;
*
* This object isn't guarded by a mutex; caller must synchronize access.
*/
class OutboundMulticast
{
public:
class OutboundMulticast {
public:
/**
* Create an uninitialized outbound multicast
*
* It must be initialized with init().
*/
OutboundMulticast() {}
OutboundMulticast()
{
}
/**
* Initialize outbound multicast
@ -62,33 +62,42 @@ public:
* @throws std::out_of_range Data too large to fit in a MULTICAST_FRAME
*/
void init(
const RuntimeEnvironment *RR,
const RuntimeEnvironment* RR,
uint64_t timestamp,
uint64_t nwid,
bool disableCompression,
unsigned int limit,
unsigned int gatherLimit,
const MAC &src,
const MulticastGroup &dest,
const MAC& src,
const MulticastGroup& dest,
unsigned int etherType,
const void *payload,
const void* payload,
unsigned int len);
/**
* @return Multicast creation time
*/
inline uint64_t timestamp() const { return _timestamp; }
inline uint64_t timestamp() const
{
return _timestamp;
}
/**
* @param now Current time
* @return True if this multicast is expired (has exceeded transmit timeout)
*/
inline bool expired(int64_t now) const { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); }
inline bool expired(int64_t now) const
{
return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT);
}
/**
* @return True if this outbound multicast has been sent to enough peers
*/
inline bool atLimit() const { return (_alreadySentTo.size() >= _limit); }
inline bool atLimit() const
{
return (_alreadySentTo.size() >= _limit);
}
/**
* Just send without checking log
@ -97,7 +106,7 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param toAddr Destination address
*/
void sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr);
void sendOnly(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr);
/**
* Just send and log but do not check sent log
@ -106,10 +115,10 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param toAddr Destination address
*/
inline void sendAndLog(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr)
inline void sendAndLog(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr)
{
_alreadySentTo.push_back(toAddr);
sendOnly(RR,tPtr,toAddr);
sendOnly(RR, tPtr, toAddr);
}
/**
@ -117,7 +126,7 @@ public:
*
* @param toAddr Address to log as sent
*/
inline void logAsSent(const Address &toAddr)
inline void logAsSent(const Address& toAddr)
{
_alreadySentTo.push_back(toAddr);
}
@ -130,17 +139,18 @@ public:
* @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,void *tPtr,const Address &toAddr)
inline bool sendIfNew(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr)
{
if (std::find(_alreadySentTo.begin(),_alreadySentTo.end(),toAddr) == _alreadySentTo.end()) {
sendAndLog(RR,tPtr,toAddr);
if (std::find(_alreadySentTo.begin(), _alreadySentTo.end(), toAddr) == _alreadySentTo.end()) {
sendAndLog(RR, tPtr, toAddr);
return true;
} else {
}
else {
return false;
}
}
private:
private:
uint64_t _timestamp;
uint64_t _nwid;
MAC _macSrc;
@ -148,11 +158,11 @@ private:
unsigned int _limit;
unsigned int _frameLen;
unsigned int _etherType;
Packet _packet,_tmp;
Packet _packet, _tmp;
std::vector<Address> _alreadySentTo;
uint8_t _frameData[ZT_MAX_MTU];
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,21 +14,19 @@
#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 "AES.hpp"
#include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Poly1305.hpp"
#include "Salsa20.hpp"
#include "AES.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include <iostream>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
/**
* Protocol version -- incremented only for major changes
@ -221,12 +219,12 @@
#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_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
/**
@ -240,12 +238,12 @@
#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_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
#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
@ -264,89 +262,89 @@
// 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_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_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_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_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_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_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_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_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_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_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_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)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT + 4)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT + 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_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_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_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_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_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_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_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)
// ---------------------------------------------------------------------------
@ -388,9 +386,8 @@ namespace ZeroTier {
* 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:
class Packet : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH> {
public:
/**
* A packet fragment
*
@ -417,22 +414,17 @@ public:
* 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>()
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) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
template <unsigned int C2> Fragment(const Buffer<C2>& b) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
{
}
Fragment(const void *data,unsigned int len) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data,len)
Fragment(const void* data, unsigned int len) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data, len)
{
}
@ -445,9 +437,9 @@ public:
* @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off)
* @param fragTotal Total number of fragments (including 0)
*/
Fragment(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal)
Fragment(const Packet& p, unsigned int fragStart, unsigned int fragLen, unsigned int fragNo, unsigned int fragTotal)
{
init(p,fragStart,fragLen,fragNo,fragTotal);
init(p, fragStart, fragLen, fragNo, fragTotal);
}
/**
@ -459,7 +451,7 @@ public:
* @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off)
* @param fragTotal Total number of fragments (including 0)
*/
inline void init(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal)
inline void init(const Packet& p, unsigned int fragStart, unsigned int fragLen, unsigned int fragNo, unsigned int fragTotal)
{
if ((fragStart + fragLen) > p.size()) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
@ -467,13 +459,13 @@ public:
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);
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);
memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD, fragLen), p.field(fragStart, fragLen), fragLen);
}
/**
@ -481,32 +473,50 @@ public:
*
* @return Destination ZT address
*/
inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
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); }
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); }
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); }
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); }
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]); }
inline unsigned int hops() const
{
return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]);
}
/**
* Increment this packet's hop count
@ -519,14 +529,17 @@ public:
/**
* @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); }
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
inline const unsigned char* payload() const
{
return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD);
return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD, size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD);
}
};
@ -793,12 +806,12 @@ public:
*
* ERROR response payload:
* <[8] 64-bit network ID>
* <[2] 16-bit length of error-related data (optional)>
* <[...] error-related data (optional)>
*
* Error related data is a Dictionary containing things like a URL
* for authentication or a human-readable error message, and is
* optional and may be absent or empty.
* <[2] 16-bit length of error-related data (optional)>
* <[...] error-related data (optional)>
*
* Error related data is a Dictionary containing things like a URL
* for authentication or a human-readable error message, and is
* optional and may be absent or empty.
*/
VERB_NETWORK_CONFIG_REQUEST = 0x0b,
@ -1056,8 +1069,7 @@ public:
/**
* Error codes for VERB_ERROR
*/
enum ErrorCode
{
enum ErrorCode {
/* No error, not actually used in transit */
ERROR_NONE = 0x00,
@ -1085,18 +1097,15 @@ public:
/* Multicasts to this group are not wanted */
ERROR_UNWANTED_MULTICAST = 0x08,
/* Network requires external or 2FA authentication (e.g. SSO). */
ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09
/* Network requires external or 2FA authentication (e.g. SSO). */
ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09
};
template<unsigned int C2>
Packet(const Buffer<C2> &b) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
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)
Packet(const void* data, unsigned int len) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data, len)
{
}
@ -1107,11 +1116,10 @@ public:
* 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)
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
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops
}
/**
@ -1123,10 +1131,9 @@ public:
* @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)
Packet(const Packet& prototype, const Address& dest) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(prototype)
{
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
setDestination(dest);
}
@ -1137,13 +1144,12 @@ public:
* @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)
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);
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
setDestination(dest);
setSource(source);
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
setVerb(v);
}
@ -1154,13 +1160,13 @@ public:
* @param source Source ZT address
* @param v Verb
*/
inline void reset(const Address &dest,const Address &source,const Verb v)
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);
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
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops
setVerb(v);
}
@ -1171,45 +1177,66 @@ public:
* technically different but otherwise identical copies of the same
* packet.
*/
inline void newInitializationVector() { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); }
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); }
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); }
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); }
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); }
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); }
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); }
inline bool fragmented() const
{
return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0);
}
/**
* Set this packet's fragmented flag
@ -1220,7 +1247,8 @@ public:
{
if (f) {
(*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED;
} else {
}
else {
(*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED);
}
}
@ -1228,19 +1256,25 @@ public:
/**
* @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); }
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); }
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];
unsigned char& b = (*this)[ZT_PACKET_IDX_FLAGS];
b = (b & 0xf8) | ((b + 1) & 0x07);
}
@ -1265,12 +1299,13 @@ public:
*/
inline void setCipher(unsigned int c)
{
unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS];
b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH
unsigned char& b = (*this)[ZT_PACKET_IDX_FLAGS];
b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH
// Set 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 {
}
else {
b &= (~ZT_PROTO_FLAG_ENCRYPTED);
}
}
@ -1280,7 +1315,10 @@ public:
*
* @return Trusted path ID (from MAC field)
*/
inline uint64_t trustedPathId() const { return at<uint64_t>(ZT_PACKET_IDX_MAC); }
inline uint64_t trustedPathId() const
{
return at<uint64_t>(ZT_PACKET_IDX_MAC);
}
/**
* Set this packet's trusted path ID and set the cipher spec to trusted path
@ -1290,7 +1328,7 @@ public:
inline void setTrusted(const uint64_t tpid)
{
setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH);
setAt(ZT_PACKET_IDX_MAC,tpid);
setAt(ZT_PACKET_IDX_MAC, tpid);
}
/**
@ -1304,7 +1342,10 @@ public:
*
* @return Packet ID
*/
inline uint64_t packetId() const { return at<uint64_t>(ZT_PACKET_IDX_IV); }
inline uint64_t packetId() const
{
return at<uint64_t>(ZT_PACKET_IDX_IV);
}
/**
* Set packet verb
@ -1314,22 +1355,34 @@ public:
*
* @param v New packet verb
*/
inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; }
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); }
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)); }
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); }
inline const unsigned char* payload() const
{
return field(ZT_PACKET_IDX_PAYLOAD, size() - ZT_PACKET_IDX_PAYLOAD);
}
/**
* Armor packet for transport
@ -1338,7 +1391,7 @@ public:
* @param encryptPayload If true, encrypt packet payload, else just MAC
* @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV
*/
void armor(const void *key,bool encryptPayload,const AES aesKeys[2]);
void armor(const void* key, bool encryptPayload, const AES aesKeys[2]);
/**
* Verify and (if encrypted) decrypt packet
@ -1351,7 +1404,7 @@ public:
* @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV
* @return False if packet is invalid or failed MAC authenticity check
*/
bool dearmor(const void *key,const AES aesKeys[2]);
bool dearmor(const void* key, const AES aesKeys[2]);
/**
* Encrypt/decrypt a separately armored portion of a packet
@ -1366,7 +1419,7 @@ public:
* @param start Start of encrypted portion
* @param len Length of encrypted portion
*/
void cryptField(const void *key,unsigned int start,unsigned int len);
void cryptField(const void* key, unsigned int start, unsigned int len);
/**
* Attempt to compress payload if not already (must be unencrypted)
@ -1390,7 +1443,7 @@ public:
*/
bool uncompress();
private:
private:
static const unsigned char ZERO_KEY[32];
/**
@ -1404,13 +1457,13 @@ private:
* @param in Input key (32 bytes)
* @param out Output buffer (32 bytes)
*/
inline void _salsa20MangleKey(const unsigned char *in,unsigned char *out) const
inline void _salsa20MangleKey(const unsigned char* in, unsigned char* out) const
{
const unsigned char *d = (const unsigned char *)data();
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
for (unsigned int i = 0; i < 18; ++i) { // 8 + (ZT_ADDRESS_LENGTH * 2) == 18
out[i] = in[i] ^ d[i];
}
@ -1422,15 +1475,15 @@ private:
// 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
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) {
for (unsigned int i = 21; i < 32; ++i) {
out[i] = in[i];
}
}
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -13,9 +13,9 @@
#include "PacketMultiplexer.hpp"
#include "Constants.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Constants.hpp"
#include <stdio.h>
#include <stdlib.h>
@ -30,12 +30,12 @@ PacketMultiplexer::PacketMultiplexer(const RuntimeEnvironment* renv)
void PacketMultiplexer::putFrame(void* tPtr, uint64_t nwid, void** nuptr, const MAC& source, const MAC& dest, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len, unsigned int flowId)
{
#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__WINDOWS__)
RR->node->putFrame(tPtr,nwid,nuptr,source,dest,etherType,vlanId,(const void *)data,len);
RR->node->putFrame(tPtr, nwid, nuptr, source, dest, etherType, vlanId, (const void*)data, len);
return;
#endif
if (!_enabled) {
RR->node->putFrame(tPtr,nwid,nuptr,source,dest,etherType,vlanId,(const void *)data,len);
if (! _enabled) {
RR->node->putFrame(tPtr, nwid, nuptr, source, dest, etherType, vlanId, (const void*)data, len);
return;
}

View file

@ -12,18 +12,19 @@
/****/
#include "Path.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
namespace ZeroTier {
bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now)
bool Path::send(const RuntimeEnvironment* RR, void* tPtr, const void* data, unsigned int len, int64_t now)
{
if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) {
if (RR->node->putPacket(tPtr, _localSocket, _addr, data, len)) {
_lastOut = now;
return true;
}
return false;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,20 +14,19 @@
#ifndef ZT_PATH_HPP
#define ZT_PATH_HPP
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdexcept>
#include <algorithm>
#include "AtomicCounter.hpp"
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
#include "Utils.hpp"
#include "Packet.hpp"
#include "RingBuffer.hpp"
#include "SharedPtr.hpp"
#include "Utils.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/**
* Maximum return value of preferenceRank()
@ -41,89 +40,102 @@ class RuntimeEnvironment;
/**
* A path across the physical network
*/
class Path
{
class Path {
friend class SharedPtr<Path>;
friend class Bond;
public:
public:
/**
* Efficient unique key for paths in a Hashtable
*/
class HashKey
{
public:
HashKey() {}
class HashKey {
public:
HashKey()
{
}
HashKey(const int64_t l,const InetAddress &r)
HashKey(const int64_t l, const InetAddress& r)
{
if (r.ss_family == AF_INET) {
_k[0] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_addr.s_addr;
_k[1] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_port;
_k[0] = (uint64_t)reinterpret_cast<const struct sockaddr_in*>(&r)->sin_addr.s_addr;
_k[1] = (uint64_t)reinterpret_cast<const struct sockaddr_in*>(&r)->sin_port;
_k[2] = (uint64_t)l;
} else if (r.ss_family == AF_INET6) {
memcpy(_k,reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
_k[2] = ((uint64_t)reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port << 32) ^ (uint64_t)l;
} else {
memcpy(_k,&r,std::min(sizeof(_k),sizeof(InetAddress)));
}
else if (r.ss_family == AF_INET6) {
memcpy(_k, reinterpret_cast<const struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, 16);
_k[2] = ((uint64_t)reinterpret_cast<const struct sockaddr_in6*>(&r)->sin6_port << 32) ^ (uint64_t)l;
}
else {
memcpy(_k, &r, std::min(sizeof(_k), sizeof(InetAddress)));
_k[2] += (uint64_t)l;
}
}
inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); }
inline unsigned long hashCode() const
{
return (unsigned long)(_k[0] + _k[1] + _k[2]);
}
inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); }
inline bool operator!=(const HashKey &k) const { return (!(*this == k)); }
inline bool operator==(const HashKey& k) const
{
return ((_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]));
}
inline bool operator!=(const HashKey& k) const
{
return (! (*this == k));
}
private:
private:
uint64_t _k[3];
};
Path() :
_lastOut(0),
_lastIn(0),
_lastTrustEstablishedPacketReceived(0),
_lastEchoRequestReceived(0),
_localPort(0),
_localSocket(-1),
_latencyMean(0.0),
_latencyVariance(0.0),
_packetLossRatio(0.0),
_packetErrorRatio(0.0),
_assignedFlowCount(0),
_valid(true),
_eligible(false),
_bonded(false),
_mtu(0),
_givenLinkSpeed(0),
_relativeQuality(0),
_latency(0xffff),
_addr(),
_ipScope(InetAddress::IP_SCOPE_NONE)
{}
Path()
: _lastOut(0)
, _lastIn(0)
, _lastTrustEstablishedPacketReceived(0)
, _lastEchoRequestReceived(0)
, _localPort(0)
, _localSocket(-1)
, _latencyMean(0.0)
, _latencyVariance(0.0)
, _packetLossRatio(0.0)
, _packetErrorRatio(0.0)
, _assignedFlowCount(0)
, _valid(true)
, _eligible(false)
, _bonded(false)
, _mtu(0)
, _givenLinkSpeed(0)
, _relativeQuality(0)
, _latency(0xffff)
, _addr()
, _ipScope(InetAddress::IP_SCOPE_NONE)
{
}
Path(const int64_t localSocket,const InetAddress &addr) :
_lastOut(0),
_lastIn(0),
_lastTrustEstablishedPacketReceived(0),
_lastEchoRequestReceived(0),
_localPort(0),
_localSocket(localSocket),
_latencyMean(0.0),
_latencyVariance(0.0),
_packetLossRatio(0.0),
_packetErrorRatio(0.0),
_assignedFlowCount(0),
_valid(true),
_eligible(false),
_bonded(false),
_mtu(0),
_givenLinkSpeed(0),
_relativeQuality(0),
_latency(0xffff),
_addr(addr),
_ipScope(addr.ipScope())
{}
Path(const int64_t localSocket, const InetAddress& addr)
: _lastOut(0)
, _lastIn(0)
, _lastTrustEstablishedPacketReceived(0)
, _lastEchoRequestReceived(0)
, _localPort(0)
, _localSocket(localSocket)
, _latencyMean(0.0)
, _latencyVariance(0.0)
, _packetLossRatio(0.0)
, _packetErrorRatio(0.0)
, _assignedFlowCount(0)
, _valid(true)
, _eligible(false)
, _bonded(false)
, _mtu(0)
, _givenLinkSpeed(0)
, _relativeQuality(0)
, _latency(0xffff)
, _addr(addr)
, _ipScope(addr.ipScope())
{
}
/**
* Called when a packet is received from this remote path, regardless of content
@ -138,7 +150,10 @@ public:
/**
* Set time last trusted packet was received (done in Peer::received())
*/
inline void trustedPacketReceived(const uint64_t t) { _lastTrustEstablishedPacketReceived = t; }
inline void trustedPacketReceived(const uint64_t t)
{
_lastTrustEstablishedPacketReceived = t;
}
/**
* Send a packet via this path (last out time is also updated)
@ -150,14 +165,17 @@ public:
* @param now Current time
* @return True if transport reported success
*/
bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now);
bool send(const RuntimeEnvironment* RR, void* tPtr, const void* data, unsigned int len, int64_t now);
/**
* Manually update last sent time
*
* @param t Time of send
*/
inline void sent(const int64_t t) { _lastOut = t; }
inline void sent(const int64_t t)
{
_lastOut = t;
}
/**
* Update path latency with a new measurement
@ -169,7 +187,8 @@ public:
unsigned int pl = _latency;
if (pl < 0xffff) {
_latency = (pl + l) / 2;
} else {
}
else {
_latency = l;
}
}
@ -177,27 +196,42 @@ public:
/**
* @return Local socket as specified by external code
*/
inline int64_t localSocket() const { return _localSocket; }
inline int64_t localSocket() const
{
return _localSocket;
}
/**
* @return Local port corresponding to the localSocket
*/
inline int64_t localPort() const { return _localPort; }
inline int64_t localPort() const
{
return _localPort;
}
/**
* @return Physical address
*/
inline const InetAddress &address() const { return _addr; }
inline const InetAddress& address() const
{
return _addr;
}
/**
* @return IP scope -- faster shortcut for address().ipScope()
*/
inline InetAddress::IpScope ipScope() const { return _ipScope; }
inline InetAddress::IpScope ipScope() const
{
return _ipScope;
}
/**
* @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms
*/
inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); }
inline bool trustEstablished(const int64_t now) const
{
return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION);
}
/**
* @return Preference rank, higher == better
@ -206,7 +240,7 @@ public:
{
// This causes us to rank paths in order of IP scope rank (see InetAddress.hpp) but
// within each IP scope class to prefer IPv6 over IPv4.
return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) );
return (((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6));
}
/**
@ -218,10 +252,10 @@ public:
* @param a Address to check
* @return True if address is good for ZeroTier path use
*/
static inline bool isAddressValidForPath(const InetAddress &a)
static inline bool isAddressValidForPath(const InetAddress& a)
{
if ((a.ss_family == AF_INET)||(a.ss_family == AF_INET6)) {
switch(a.ipScope()) {
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
@ -237,8 +271,8 @@ public:
// 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)) {
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;
}
}
@ -253,7 +287,10 @@ public:
/**
* @return Latency or 0xffff if unknown
*/
inline unsigned int latency() const { return _latency; }
inline unsigned int latency() const
{
return _latency;
}
/**
* @return Path quality -- lower is better
@ -261,41 +298,57 @@ public:
inline long quality(const int64_t now) const
{
const int l = (long)_latency;
const int age = (long)std::min((now - _lastIn),(int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow
const int age = (long)std::min((now - _lastIn), (int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow
return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (long)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1));
}
/**
* @return True if this path is alive (receiving heartbeats)
*/
inline bool alive(const int64_t now) const {
inline bool alive(const int64_t now) const
{
return (now - _lastIn) < (ZT_PATH_HEARTBEAT_PERIOD + 5000);
}
/**
* @return True if this path needs a heartbeat
*/
inline bool needsHeartbeat(const int64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); }
inline bool needsHeartbeat(const int64_t now) const
{
return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD);
}
/**
* @return Last time we sent something
*/
inline int64_t lastOut() const { return _lastOut; }
inline int64_t lastOut() const
{
return _lastOut;
}
/**
* @return Last time we received anything
*/
inline int64_t lastIn() const { return _lastIn; }
inline int64_t lastIn() const
{
return _lastIn;
}
/**
* @return the age of the path in terms of receiving packets
*/
inline int64_t age(int64_t now) { return (now - _lastIn); }
inline int64_t age(int64_t now)
{
return (now - _lastIn);
}
/**
* @return Time last trust-established packet was received
*/
inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; }
inline int64_t lastTrustEstablishedPacketReceived() const
{
return _lastTrustEstablishedPacketReceived;
}
/**
* Rate limit gate for inbound ECHO requests
@ -312,69 +365,102 @@ public:
/**
* @return Mean latency as reported by the bonding layer
*/
inline float latencyMean() const { return _latencyMean; }
inline float latencyMean() const
{
return _latencyMean;
}
/**
* @return Latency variance as reported by the bonding layer
*/
inline float latencyVariance() const { return _latencyVariance; }
inline float latencyVariance() const
{
return _latencyVariance;
}
/**
* @return Packet Loss Ratio as reported by the bonding layer
*/
inline float packetLossRatio() const { return _packetLossRatio; }
inline float packetLossRatio() const
{
return _packetLossRatio;
}
/**
* @return Packet Error Ratio as reported by the bonding layer
*/
inline float packetErrorRatio() const { return _packetErrorRatio; }
inline float packetErrorRatio() const
{
return _packetErrorRatio;
}
/**
* @return Number of flows assigned to this path
*/
inline unsigned int assignedFlowCount() const { return _assignedFlowCount; }
inline unsigned int assignedFlowCount() const
{
return _assignedFlowCount;
}
/**
* @return Whether this path is valid as reported by the bonding layer. The bonding layer
* actually checks with Phy to see if the interface is still up
*/
inline bool valid() const { return _valid; }
inline bool valid() const
{
return _valid;
}
/**
* @return Whether this path is eligible for use in a bond as reported by the bonding layer
*/
inline bool eligible() const { return _eligible; }
inline bool eligible() const
{
return _eligible;
}
/**
* @return Whether this path is bonded as reported by the bonding layer
*/
inline bool bonded() const { return _bonded; }
inline bool bonded() const
{
return _bonded;
}
/**
* @return Whether the user-specified MTU for this path (determined by MTU for parent link)
*/
inline uint16_t mtu() const { return _mtu; }
inline uint16_t mtu() const
{
return _mtu;
}
/**
* @return Given link capacity as reported by the bonding layer
*/
inline uint32_t givenLinkSpeed() const { return _givenLinkSpeed; }
inline uint32_t givenLinkSpeed() const
{
return _givenLinkSpeed;
}
/**
* @return Path's quality as reported by the bonding layer
*/
inline float relativeQuality() const { return _relativeQuality; }
inline float relativeQuality() const
{
return _relativeQuality;
}
/**
* @return Physical interface name that this path lives on
*/
char *ifname() {
char* ifname()
{
return _ifname;
}
private:
char _ifname[ZT_MAX_PHYSIFNAME] = { };
private:
char _ifname[ZT_MAX_PHYSIFNAME] = {};
volatile int64_t _lastOut;
volatile int64_t _lastIn;
@ -399,10 +485,10 @@ private:
volatile unsigned int _latency;
InetAddress _addr;
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
AtomicCounter __refCount;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,24 +11,25 @@
*/
/****/
#include "Peer.hpp"
#include "../version.h"
#include "Constants.hpp"
#include "Peer.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "SelfAwareness.hpp"
#include "Packet.hpp"
#include "Trace.hpp"
#include "InetAddress.hpp"
#include "RingBuffer.hpp"
#include "Utils.hpp"
#include "Metrics.hpp"
#include "Network.hpp"
#include "Packet.hpp"
#include "RingBuffer.hpp"
#include "SelfAwareness.hpp"
#include "Switch.hpp"
#include "Trace.hpp"
#include "Utils.hpp"
namespace ZeroTier {
static unsigned char s_freeRandomByteCounter = 0;
Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity)
Peer::Peer(const RuntimeEnvironment* renv, const Identity& myIdentity, const Identity& peerIdentity)
: RR(renv)
, _lastReceive(0)
, _lastNontrivialReceive(0)
@ -52,29 +53,29 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
, _localMultipathSupported(false)
, _lastComputedAggregateMeanLatency(0)
#ifndef ZT_NO_PEER_METRICS
, _peer_latency{Metrics::peer_latency.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}}, std::vector<uint64_t>{1,3,6,10,30,60,100,300,600,1000})}
, _alive_path_count{Metrics::peer_path_count.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())},{"status","alive"}})}
, _dead_path_count{Metrics::peer_path_count.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())},{"status","dead"}})}
, _incoming_packet{Metrics::peer_packets.Add({{"direction", "rx"},{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})}
, _outgoing_packet{Metrics::peer_packets.Add({{"direction", "tx"},{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})}
, _packet_errors{Metrics::peer_packet_errors.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})}
, _peer_latency { Metrics::peer_latency.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }, std::vector<uint64_t> { 1, 3, 6, 10, 30, 60, 100, 300, 600, 1000 }) }
, _alive_path_count { Metrics::peer_path_count.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) }, { "status", "alive" } }) }
, _dead_path_count { Metrics::peer_path_count.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) }, { "status", "dead" } }) }
, _incoming_packet { Metrics::peer_packets.Add({ { "direction", "rx" }, { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }) }
, _outgoing_packet { Metrics::peer_packets.Add({ { "direction", "tx" }, { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }) }
, _packet_errors { Metrics::peer_packet_errors.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }) }
#endif
{
if (!myIdentity.agree(peerIdentity,_key)) {
if (! myIdentity.agree(peerIdentity, _key)) {
throw ZT_EXCEPTION_INVALID_ARGUMENT;
}
uint8_t ktmp[ZT_SYMMETRIC_KEY_SIZE];
KBKDFHMACSHA384(_key,ZT_KBKDF_LABEL_AES_GMAC_SIV_K0,0,0,ktmp);
KBKDFHMACSHA384(_key, ZT_KBKDF_LABEL_AES_GMAC_SIV_K0, 0, 0, ktmp);
_aesKeys[0].init(ktmp);
KBKDFHMACSHA384(_key,ZT_KBKDF_LABEL_AES_GMAC_SIV_K1,0,0,ktmp);
KBKDFHMACSHA384(_key, ZT_KBKDF_LABEL_AES_GMAC_SIV_K1, 0, 0, ktmp);
_aesKeys[1].init(ktmp);
Utils::burn(ktmp,ZT_SYMMETRIC_KEY_SIZE);
Utils::burn(ktmp, ZT_SYMMETRIC_KEY_SIZE);
}
void Peer::received(
void *tPtr,
const SharedPtr<Path> &path,
void* tPtr,
const SharedPtr<Path>& path,
const unsigned int hops,
const uint64_t packetId,
const unsigned int payloadLength,
@ -114,7 +115,7 @@ void Peer::received(
bool havePath = false;
{
Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if (_paths[i].p == path) {
_paths[i].lr = now;
@ -123,25 +124,26 @@ void Peer::received(
}
// If same address on same interface then don't learn unless existing path isn't alive (prevents learning loop)
if (_paths[i].p->address().ipsEqual(path->address()) && _paths[i].p->localSocket() == path->localSocket()) {
if (_paths[i].p->alive(now) && !_bond) {
if (_paths[i].p->alive(now) && ! _bond) {
havePath = true;
break;
}
}
} else {
}
else {
break;
}
}
}
if ( (!havePath) && RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address()) ) {
if ((! havePath) && RR->node->shouldUsePathForZeroTierTraffic(tPtr, _id.address(), path->localSocket(), path->address())) {
if (verb == Packet::VERB_OK) {
Mutex::Lock _l(_paths_m);
unsigned int oldestPathIdx = ZT_MAX_PEER_NETWORK_PATHS;
unsigned int oldestPathAge = 0;
unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
// Keep track of oldest path as a last resort option
unsigned int currAge = _paths[i].p->age(now);
@ -151,13 +153,14 @@ void Peer::received(
}
if (_paths[i].p->address().ipsEqual(path->address())) {
if (_paths[i].p->localSocket() == path->localSocket()) {
if (!_paths[i].p->alive(now)) {
if (! _paths[i].p->alive(now)) {
replacePath = i;
break;
}
}
}
} else {
}
else {
replacePath = i;
break;
}
@ -171,30 +174,33 @@ void Peer::received(
_paths[replacePath].p = path;
_paths[replacePath].priority = 1;
Mutex::Lock _l(_bond_m);
if(_bond) {
if (_bond) {
_bond->nominatePathToBond(_paths[replacePath].p, now);
}
}
} else {
}
else {
Mutex::Lock ltl(_lastTriedPath_m);
bool triedTooRecently = false;
for(std::list< std::pair< Path *, int64_t > >::iterator i(_lastTriedPath.begin());i!=_lastTriedPath.end();) {
for (std::list<std::pair<Path*, int64_t> >::iterator i(_lastTriedPath.begin()); i != _lastTriedPath.end();) {
if ((now - i->second) > 1000) {
_lastTriedPath.erase(i++);
} else if (i->first == path.ptr()) {
}
else if (i->first == path.ptr()) {
++i;
triedTooRecently = true;
} else {
}
else {
++i;
}
}
if (!triedTooRecently) {
_lastTriedPath.push_back(std::pair< Path *, int64_t >(path.ptr(), now));
attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true);
if (! triedTooRecently) {
_lastTriedPath.push_back(std::pair<Path*, int64_t>(path.ptr(), now));
attemptToContactAt(tPtr, path->localSocket(), path->address(), now, true);
path->sent(now);
RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb);
RR->t->peerConfirmingUnknownPath(tPtr, networkId, *this, path, packetId, verb);
}
}
}
@ -212,30 +218,30 @@ void Peer::received(
std::vector<InetAddress> pathsToPush(RR->node->directPaths());
std::vector<InetAddress> ma = RR->sa->whoami();
pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end());
if (!pathsToPush.empty()) {
if (! pathsToPush.empty()) {
std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
while (p != pathsToPush.end()) {
Packet *const outp = new Packet(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
outp->addSize(2); // leave room for count
Packet* const outp = new Packet(_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)) {
while ((p != pathsToPush.end()) && ((outp->size() + 24) < 1200)) {
uint8_t addressType = 4;
switch(p->ss_family) {
switch (p->ss_family) {
case AF_INET:
break;
case AF_INET6:
addressType = 6;
break;
default: // we currently only push IP addresses
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((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(p->rawIpData(), ((addressType == 4) ? 4 : 16));
outp->append((uint16_t)p->port());
++count;
@ -243,11 +249,11 @@ void Peer::received(
}
if (count) {
Metrics::pkt_push_direct_paths_out++;
outp->setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count);
outp->setAt(ZT_PACKET_IDX_PAYLOAD, (uint16_t)count);
outp->compress();
outp->armor(_key,true,aesKeysIfSupported());
outp->armor(_key, true, aesKeysIfSupported());
Metrics::pkt_push_direct_paths_out++;
path->send(RR,tPtr,outp->data(),outp->size(),now);
path->send(RR, tPtr, outp->data(), outp->size(), now);
}
delete outp;
}
@ -260,7 +266,7 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
{
Mutex::Lock _l(_paths_m);
Mutex::Lock _lb(_bond_m);
if(_bond && _bond->isReady()) {
if (_bond && _bond->isReady()) {
return _bond->getAppropriatePath(now, flowId);
}
unsigned int bestPath = ZT_MAX_PEER_NETWORK_PATHS;
@ -269,16 +275,17 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
* use the old path quality metric from protocol version 9.
*/
long bestPathQuality = 2147483647;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if ((includeExpired)||((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION)) {
if ((includeExpired) || ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION)) {
const long q = _paths[i].p->quality(now) / _paths[i].priority;
if (q <= bestPathQuality) {
bestPathQuality = q;
bestPath = i;
}
}
} else {
}
else {
break;
}
}
@ -288,17 +295,17 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
return SharedPtr<Path>();
}
void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &other) const
void Peer::introduce(void* const tPtr, const int64_t now, const SharedPtr<Peer>& other) const
{
unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1];
unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1];
long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1];
long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1];
unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1];
unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1];
long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1];
long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1];
for(int i=0;i<=ZT_INETADDRESS_MAX_SCOPE;++i) {
unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
for (int i = 0; i <= ZT_INETADDRESS_MAX_SCOPE; ++i) {
myBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS;
myBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS;
myBestV4QualityByScope[i] = 2147483647;
@ -311,11 +318,11 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
Mutex::Lock _l1(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
const long q = _paths[i].p->quality(now) / _paths[i].priority;
const unsigned int s = (unsigned int)_paths[i].p->ipScope();
switch(_paths[i].p->address().ss_family) {
switch (_paths[i].p->address().ss_family) {
case AF_INET:
if (q <= myBestV4QualityByScope[s]) {
myBestV4QualityByScope[s] = q;
@ -329,18 +336,19 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
}
break;
}
} else {
}
else {
break;
}
}
Mutex::Lock _l2(other->_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (other->_paths[i].p) {
const long q = other->_paths[i].p->quality(now) / other->_paths[i].priority;
const unsigned int s = (unsigned int)other->_paths[i].p->ipScope();
switch(other->_paths[i].p->address().ss_family) {
switch (other->_paths[i].p->address().ss_family) {
case AF_INET:
if (q <= theirBestV4QualityByScope[s]) {
theirBestV4QualityByScope[s] = q;
@ -354,7 +362,8 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
}
break;
}
} else {
}
else {
break;
}
}
@ -362,13 +371,13 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
unsigned int mine = ZT_MAX_PEER_NETWORK_PATHS;
unsigned int theirs = ZT_MAX_PEER_NETWORK_PATHS;
for(int s=ZT_INETADDRESS_MAX_SCOPE;s>=0;--s) {
if ((myBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)&&(theirBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) {
for (int s = ZT_INETADDRESS_MAX_SCOPE; s >= 0; --s) {
if ((myBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS) && (theirBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) {
mine = myBestV6ByScope[s];
theirs = theirBestV6ByScope[s];
break;
}
if ((myBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)&&(theirBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) {
if ((myBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS) && (theirBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) {
mine = myBestV4ByScope[s];
theirs = theirBestV4ByScope[s];
break;
@ -376,55 +385,58 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
}
if (mine != ZT_MAX_PEER_NETWORK_PATHS) {
unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for black magickal NAT-t reasons
unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for black magickal NAT-t reasons
const unsigned int completed = alt + 2;
while (alt != completed) {
if ((alt & 1) == 0) {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS);
Packet outp(_id.address(), RR->identity.address(), Packet::VERB_RENDEZVOUS);
outp.append((uint8_t)0);
other->_id.address().appendTo(outp);
outp.append((uint16_t)other->_paths[theirs].p->address().port());
if (other->_paths[theirs].p->address().ss_family == AF_INET6) {
outp.append((uint8_t)16);
outp.append(other->_paths[theirs].p->address().rawIpData(),16);
} else {
outp.append((uint8_t)4);
outp.append(other->_paths[theirs].p->address().rawIpData(),4);
outp.append(other->_paths[theirs].p->address().rawIpData(), 16);
}
outp.armor(_key,true,aesKeysIfSupported());
else {
outp.append((uint8_t)4);
outp.append(other->_paths[theirs].p->address().rawIpData(), 4);
}
outp.armor(_key, true, aesKeysIfSupported());
Metrics::pkt_rendezvous_out++;
_paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now);
} else {
Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS);
_paths[mine].p->send(RR, tPtr, outp.data(), outp.size(), now);
}
else {
Packet outp(other->_id.address(), RR->identity.address(), Packet::VERB_RENDEZVOUS);
outp.append((uint8_t)0);
_id.address().appendTo(outp);
outp.append((uint16_t)_paths[mine].p->address().port());
if (_paths[mine].p->address().ss_family == AF_INET6) {
outp.append((uint8_t)16);
outp.append(_paths[mine].p->address().rawIpData(),16);
} else {
outp.append((uint8_t)4);
outp.append(_paths[mine].p->address().rawIpData(),4);
outp.append(_paths[mine].p->address().rawIpData(), 16);
}
outp.armor(other->_key,true,other->aesKeysIfSupported());
else {
outp.append((uint8_t)4);
outp.append(_paths[mine].p->address().rawIpData(), 4);
}
outp.armor(other->_key, true, other->aesKeysIfSupported());
Metrics::pkt_rendezvous_out++;
other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now);
other->_paths[theirs].p->send(RR, tPtr, outp.data(), outp.size(), now);
}
++alt;
}
}
}
void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now)
void Peer::sendHELLO(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now)
{
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO);
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);
RR->identity.serialize(outp, false);
atAddress.serialize(outp);
outp.append((uint64_t)RR->topology->planetWorldId());
@ -435,56 +447,58 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
std::vector<World> moons(RR->topology->moons());
std::vector<uint64_t> moonsWanted(RR->topology->moonsWanted());
outp.append((uint16_t)(moons.size() + moonsWanted.size()));
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
for (std::vector<World>::const_iterator m(moons.begin()); m != moons.end(); ++m) {
outp.append((uint8_t)m->type());
outp.append((uint64_t)m->id());
outp.append((uint64_t)m->timestamp());
}
for(std::vector<uint64_t>::const_iterator m(moonsWanted.begin());m!=moonsWanted.end();++m) {
for (std::vector<uint64_t>::const_iterator m(moonsWanted.begin()); m != moonsWanted.end(); ++m) {
outp.append((uint8_t)World::TYPE_MOON);
outp.append(*m);
outp.append((uint64_t)0);
}
outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt);
outp.cryptField(_key, startCryptedPortionAt, outp.size() - startCryptedPortionAt);
Metrics::pkt_hello_out++;
if (atAddress) {
outp.armor(_key,false,nullptr); // false == don't encrypt full payload, but add MAC
outp.armor(_key, false, nullptr); // false == don't encrypt full payload, but add MAC
RR->node->expectReplyTo(outp.packetId());
RR->node->putPacket(tPtr,RR->node->lowBandwidthModeEnabled() ? localSocket : -1,atAddress,outp.data(),outp.size());
} else {
RR->node->putPacket(tPtr, RR->node->lowBandwidthModeEnabled() ? localSocket : -1, atAddress, outp.data(), outp.size());
}
else {
RR->node->expectReplyTo(outp.packetId());
RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC
RR->sw->send(tPtr, outp, false); // false == don't encrypt full payload, but add MAC
}
}
void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello)
void Peer::attemptToContactAt(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now, bool sendFullHello)
{
if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
outp.armor(_key,true,aesKeysIfSupported());
if ((! sendFullHello) && (_vProto >= 5) && (! ((_vMajor == 1) && (_vMinor == 1) && (_vRevision == 0)))) {
Packet outp(_id.address(), RR->identity.address(), Packet::VERB_ECHO);
outp.armor(_key, true, aesKeysIfSupported());
Metrics::pkt_echo_out++;
RR->node->expectReplyTo(outp.packetId());
RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size());
} else {
sendHELLO(tPtr,localSocket,atAddress,now);
RR->node->putPacket(tPtr, localSocket, atAddress, outp.data(), outp.size());
}
else {
sendHELLO(tPtr, localSocket, atAddress, now);
}
}
void Peer::tryMemorizedPath(void *tPtr,int64_t now)
void Peer::tryMemorizedPath(void* tPtr, int64_t now)
{
if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) {
_lastTriedMemorizedPath = now;
InetAddress mp;
if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) {
attemptToContactAt(tPtr,-1,mp,now,true);
if (RR->node->externalPathLookup(tPtr, _id.address(), -1, mp)) {
attemptToContactAt(tPtr, -1, mp, now, true);
}
}
}
void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
void Peer::performMultipathStateCheck(void* tPtr, int64_t now)
{
Mutex::Lock _l(_bond_m);
/**
@ -493,9 +507,9 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
*/
int numAlivePaths = 0;
bool atLeastOneNonExpired = false;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if(_paths[i].p->alive(now)) {
if (_paths[i].p->alive(now)) {
numAlivePaths++;
}
if ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) {
@ -504,21 +518,21 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
}
}
if (_bond) {
if (numAlivePaths == 0 && !atLeastOneNonExpired) {
if (numAlivePaths == 0 && ! atLeastOneNonExpired) {
_bond = SharedPtr<Bond>();
RR->bc->destroyBond(_id.address().toInt());
}
return;
}
_localMultipathSupported = ((numAlivePaths >= 1) && (RR->bc->inUse()) && (ZT_PROTO_VERSION > 9));
if (_localMultipathSupported && !_bond) {
if (_localMultipathSupported && ! _bond) {
if (RR->bc) {
_bond = RR->bc->createBond(RR, this);
/**
* Allow new bond to retroactively learn all paths known to this peer
*/
if (_bond) {
for (unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
_bond->nominatePathToBond(_paths[i].p, now);
}
@ -528,7 +542,7 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
}
}
unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
unsigned int Peer::doPingAndKeepalive(void* tPtr, int64_t now)
{
unsigned int sent = 0;
{
@ -546,31 +560,33 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
// redirects us its redirect target links override all other links and we
// let those old links expire.
long maxPriority = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
maxPriority = std::max(_paths[i].priority,maxPriority);
} else {
maxPriority = std::max(_paths[i].priority, maxPriority);
}
else {
break;
}
}
bool deletionOccurred = false;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
// Clean expired and reduced priority paths
if ( ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority) ) {
if ((sendFullHello)||(_paths[i].p->needsHeartbeat(now))) {
attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello);
if (((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority)) {
if ((sendFullHello) || (_paths[i].p->needsHeartbeat(now))) {
attemptToContactAt(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), now, sendFullHello);
_paths[i].p->sent(now);
sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2;
}
} else {
}
else {
_paths[i] = _PeerPath();
deletionOccurred = true;
}
}
if (!_paths[i].p || deletionOccurred) {
for(unsigned int j=i;j<ZT_MAX_PEER_NETWORK_PATHS;++j) {
if (! _paths[i].p || deletionOccurred) {
for (unsigned int j = i; j < ZT_MAX_PEER_NETWORK_PATHS; ++j) {
if (_paths[j].p && i != j) {
_paths[i] = _paths[j];
_paths[j] = _PeerPath();
@ -582,7 +598,7 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
}
#ifndef ZT_NO_PEER_METRICS
uint16_t alive_path_count_tmp = 0, dead_path_count_tmp = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if (_paths[i].p->alive(now)) {
alive_path_count_tmp++;
@ -602,25 +618,26 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
return sent;
}
void Peer::clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,const InetAddress &remoteAddress,const int64_t now)
void Peer::clusterRedirect(void* tPtr, const SharedPtr<Path>& originatingPath, const InetAddress& remoteAddress, const int64_t now)
{
SharedPtr<Path> np(RR->topology->getPath(originatingPath->localSocket(),remoteAddress));
RR->t->peerRedirected(tPtr,0,*this,np);
SharedPtr<Path> np(RR->topology->getPath(originatingPath->localSocket(), remoteAddress));
RR->t->peerRedirected(tPtr, 0, *this, np);
attemptToContactAt(tPtr,originatingPath->localSocket(),remoteAddress,now,true);
attemptToContactAt(tPtr, originatingPath->localSocket(), remoteAddress, now, true);
{
Mutex::Lock _l(_paths_m);
// New priority is higher than the priority of the originating path (if known)
long newPriority = 1;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if (_paths[i].p == originatingPath) {
newPriority = _paths[i].priority;
break;
}
} else {
}
else {
break;
}
}
@ -629,9 +646,9 @@ void Peer::clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,con
// Erase any paths with lower priority than this one or that are duplicate
// IPs and add this path.
unsigned int j = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if ((_paths[i].priority >= newPriority)&&(!_paths[i].p->address().ipsEqual2(remoteAddress))) {
if ((_paths[i].priority >= newPriority) && (! _paths[i].p->address().ipsEqual2(remoteAddress))) {
if (i != j) {
_paths[j] = _paths[i];
}
@ -654,24 +671,24 @@ void Peer::clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,con
}
}
void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now)
void Peer::resetWithinScope(void* tPtr, InetAddress::IpScope scope, int inetAddressFamily, int64_t now)
{
Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if ((_paths[i].p->address().ss_family == inetAddressFamily)&&(_paths[i].p->ipScope() == scope)) {
attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,false);
if ((_paths[i].p->address().ss_family == inetAddressFamily) && (_paths[i].p->ipScope() == scope)) {
attemptToContactAt(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), now, false);
_paths[i].p->sent(now);
_paths[i].lr = 0; // path will not be used unless it speaks again
_paths[i].lr = 0; // path will not be used unless it speaks again
}
} else {
}
else {
break;
}
}
}
void Peer::recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId,
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
void Peer::recordOutgoingPacket(const SharedPtr<Path>& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
{
#ifndef ZT_NO_PEER_METRICS
_outgoing_packet++;
@ -691,12 +708,11 @@ void Peer::recordIncomingInvalidPacket(const SharedPtr<Path>& path)
}
}
void Peer::recordIncomingPacket(const SharedPtr<Path> &path, const uint64_t packetId,
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
void Peer::recordIncomingPacket(const SharedPtr<Path>& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
{
if (_localMultipathSupported && _bond) {
_bond->recordIncomingPacket(path, packetId, payloadLength, verb, flowId, now);
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,27 +14,26 @@
#ifndef ZT_PEER_HPP
#define ZT_PEER_HPP
#include <vector>
#include <list>
#include "../include/ZeroTierOne.h"
#include "Constants.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp"
#include "Path.hpp"
#include "AES.hpp"
#include "Address.hpp"
#include "Utils.hpp"
#include "AtomicCounter.hpp"
#include "Bond.hpp"
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
#include "Packet.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
#include "Hashtable.hpp"
#include "Mutex.hpp"
#include "Bond.hpp"
#include "AES.hpp"
#include "Metrics.hpp"
#include "Mutex.hpp"
#include "Node.hpp"
#include "Packet.hpp"
#include "Path.hpp"
#include "RuntimeEnvironment.hpp"
#include "SharedPtr.hpp"
#include "Utils.hpp"
#include <list>
#include <vector>
#define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2))
@ -43,19 +42,19 @@ namespace ZeroTier {
/**
* Peer on P2P Network (virtual layer 1)
*/
class Peer
{
class Peer {
friend class SharedPtr<Peer>;
friend class SharedPtr<Bond>;
friend class Switch;
friend class Bond;
private:
Peer() = delete; // disabled to prevent bugs -- should not be constructed uninitialized
private:
Peer() = delete; // disabled to prevent bugs -- should not be constructed uninitialized
public:
~Peer() {
Utils::burn(_key,sizeof(_key));
public:
~Peer()
{
Utils::burn(_key, sizeof(_key));
}
/**
@ -66,17 +65,23 @@ public:
* @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);
Peer(const RuntimeEnvironment* renv, const Identity& myIdentity, const Identity& peerIdentity);
/**
* @return This peer's ZT address (short for identity().address())
*/
inline const Address &address() const { return _id.address(); }
inline const Address& address() const
{
return _id.address();
}
/**
* @return This peer's identity
*/
inline const Identity &identity() const { return _id; }
inline const Identity& identity() const
{
return _id;
}
/**
* Log receipt of an authenticated packet
@ -95,8 +100,8 @@ public:
* @param networkId Network ID if this pertains to a network, or 0 otherwise
*/
void received(
void *tPtr,
const SharedPtr<Path> &path,
void* tPtr,
const SharedPtr<Path>& path,
const unsigned int hops,
const uint64_t packetId,
const unsigned int payloadLength,
@ -114,15 +119,16 @@ public:
* @param addr Remote address
* @return True if we have an active path to this destination
*/
inline bool hasActivePathTo(int64_t now,const InetAddress &addr) const
inline bool hasActivePathTo(int64_t now, const InetAddress& addr) const
{
Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if (((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION)&&(_paths[i].p->address() == addr)) {
if (((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].p->address() == addr)) {
return true;
}
} else {
}
else {
break;
}
}
@ -139,11 +145,11 @@ public:
* @param force If true, send even if path is not alive
* @return True if we actually sent something
*/
inline bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force)
inline bool sendDirect(void* tPtr, const void* data, unsigned int len, int64_t now, bool force)
{
SharedPtr<Path> bp(getAppropriatePath(now,force));
SharedPtr<Path> bp(getAppropriatePath(now, force));
if (bp) {
return bp->send(RR,tPtr,data,len,now);
return bp->send(RR, tPtr, data, len, now);
}
return false;
}
@ -159,8 +165,7 @@ public:
* @param flowId Flow ID
* @param now Current time
*/
void recordIncomingPacket(const SharedPtr<Path> &path, const uint64_t packetId,
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
void recordIncomingPacket(const SharedPtr<Path>& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
/**
*
@ -171,8 +176,7 @@ public:
* @param flowId Flow ID
* @param now Current time
*/
void recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId,
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
void recordOutgoingPacket(const SharedPtr<Path>& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
/**
* Record an invalid incoming packet. This packet failed
@ -195,7 +199,7 @@ public:
/**
* Send VERB_RENDEZVOUS to this and another peer via the best common IP scope and path
*/
void introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &other) const;
void introduce(void* const tPtr, const int64_t now, const SharedPtr<Peer>& other) const;
/**
* Send a HELLO to this peer at a specified physical address
@ -207,7 +211,7 @@ public:
* @param atAddress Destination address
* @param now Current time
*/
void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now);
void sendHELLO(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now);
/**
* Send ECHO (or HELLO for older peers) to this peer at the given address
@ -220,7 +224,7 @@ public:
* @param now Current time
* @param sendFullHello If true, always send a full HELLO instead of just an ECHO
*/
void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello);
void attemptToContactAt(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now, bool sendFullHello);
/**
* Try a memorized or statically defined path if any are known
@ -230,14 +234,14 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param now Current time
*/
void tryMemorizedPath(void *tPtr,int64_t now);
void tryMemorizedPath(void* tPtr, int64_t now);
/**
* A check to be performed periodically which determines whether multipath communication is
* possible with this peer. This check should be performed early in the life-cycle of the peer
* as well as during the process of learning new paths.
*/
void performMultipathStateCheck(void *tPtr, int64_t now);
void performMultipathStateCheck(void* tPtr, int64_t now);
/**
* Send pings or keepalives depending on configured timeouts
@ -249,7 +253,7 @@ public:
* @param inetAddressFamily Keep this address family alive, or -1 for any
* @return 0 if nothing sent or bit mask: bit 0x1 if IPv4 sent, bit 0x2 if IPv6 sent (0x3 means both sent)
*/
unsigned int doPingAndKeepalive(void *tPtr,int64_t now);
unsigned int doPingAndKeepalive(void* tPtr, int64_t now);
/**
* Process a cluster redirect sent by this peer
@ -259,7 +263,7 @@ public:
* @param remoteAddress Remote address
* @param now Current time
*/
void clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,const InetAddress &remoteAddress,const int64_t now);
void clusterRedirect(void* tPtr, const SharedPtr<Path>& originatingPath, const InetAddress& remoteAddress, const int64_t now);
/**
* Reset paths within a given IP scope and address family
@ -274,18 +278,18 @@ public:
* @param inetAddressFamily Family e.g. AF_INET
* @param now Current time
*/
void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now);
void resetWithinScope(void* tPtr, InetAddress::IpScope scope, int inetAddressFamily, int64_t now);
/**
* @param now Current time
* @return All known paths to this peer
*/
inline std::vector< SharedPtr<Path> > paths(const int64_t now) const
inline std::vector<SharedPtr<Path> > paths(const int64_t now) const
{
std::vector< SharedPtr<Path> > pp;
std::vector<SharedPtr<Path> > pp;
Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (!_paths[i].p) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (! _paths[i].p) {
break;
}
pp.push_back(_paths[i].p);
@ -296,19 +300,31 @@ public:
/**
* @return Time of last receive of anything, whether direct or relayed
*/
inline int64_t lastReceive() const { return _lastReceive; }
inline int64_t lastReceive() const
{
return _lastReceive;
}
/**
* @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT
*/
inline bool isAlive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
inline bool isAlive(const int64_t now) const
{
return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT);
}
/**
* @return True if this peer has sent us real network traffic recently
*/
inline int64_t isActive(int64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
inline int64_t isActive(int64_t now) const
{
return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT);
}
inline int64_t lastSentFullHello() { return _lastSentFullHello; }
inline int64_t lastSentFullHello()
{
return _lastSentFullHello;
}
/**
* @return Latency in milliseconds of best/aggregate path or 0xffff if unknown / no paths
@ -317,8 +333,9 @@ public:
{
if (_localMultipathSupported) {
return (int)_lastComputedAggregateMeanLatency;
} else {
SharedPtr<Path> bp(getAppropriatePath(now,false));
}
else {
SharedPtr<Path> bp(getAppropriatePath(now, false));
if (bp) {
return (unsigned int)bp->latency();
}
@ -344,7 +361,7 @@ public:
return (~(unsigned int)0);
}
unsigned int l = latency(now);
if (!l) {
if (! l) {
l = 0xffff;
}
return (l * (((unsigned int)tsr / (ZT_PEER_PING_PERIOD + 1000)) + 1));
@ -353,7 +370,10 @@ public:
/**
* @return 256-bit secret symmetric encryption key
*/
inline const unsigned char *key() const { return _key; }
inline const unsigned char* key() const
{
return _key;
}
/**
* Set the currently known remote version of this peer's client
@ -363,7 +383,7 @@ public:
* @param vmin Minor version
* @param vrev Revision
*/
inline void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev)
inline void setRemoteVersion(unsigned int vproto, unsigned int vmaj, unsigned int vmin, unsigned int vrev)
{
_vProto = (uint16_t)vproto;
_vMajor = (uint16_t)vmaj;
@ -371,17 +391,35 @@ public:
_vRevision = (uint16_t)vrev;
}
inline unsigned int remoteVersionProtocol() const { return _vProto; }
inline unsigned int remoteVersionMajor() const { return _vMajor; }
inline unsigned int remoteVersionMinor() const { return _vMinor; }
inline unsigned int remoteVersionRevision() const { return _vRevision; }
inline unsigned int remoteVersionProtocol() const
{
return _vProto;
}
inline unsigned int remoteVersionMajor() const
{
return _vMajor;
}
inline unsigned int remoteVersionMinor() const
{
return _vMinor;
}
inline unsigned int remoteVersionRevision() const
{
return _vRevision;
}
inline bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
inline bool remoteVersionKnown() const
{
return ((_vMajor > 0) || (_vMinor > 0) || (_vRevision > 0));
}
/**
* @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms
*/
inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); }
inline bool trustEstablished(const int64_t now) const
{
return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION);
}
/**
* Rate limit gate for VERB_PUSH_DIRECT_PATHS
@ -390,7 +428,8 @@ public:
{
if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) {
++_directPathPushCutoffCount;
} else {
}
else {
_directPathPushCutoffCount = 0;
}
_lastDirectPathPushReceive = now;
@ -439,10 +478,10 @@ public:
inline bool rateGateQoS(int64_t now, SharedPtr<Path>& path)
{
Mutex::Lock _l(_bond_m);
if(_bond) {
if (_bond) {
return _bond->rateGateQoS(now, path);
}
return false; // Default behavior. If there is no bond, we drop these
return false; // Default behavior. If there is no bond, we drop these
}
/**
@ -451,7 +490,7 @@ public:
void receivedQoS(const SharedPtr<Path>& path, int64_t now, int count, uint64_t* rx_id, uint16_t* rx_ts)
{
Mutex::Lock _l(_bond_m);
if(_bond) {
if (_bond) {
_bond->receivedQoS(path, now, count, rx_id, rx_ts);
}
}
@ -462,7 +501,7 @@ public:
void processIncomingPathNegotiationRequest(uint64_t now, SharedPtr<Path>& path, int16_t remoteUtility)
{
Mutex::Lock _l(_bond_m);
if(_bond) {
if (_bond) {
_bond->processIncomingPathNegotiationRequest(now, path, remoteUtility);
}
}
@ -473,10 +512,10 @@ public:
inline bool rateGatePathNegotiation(int64_t now, SharedPtr<Path>& path)
{
Mutex::Lock _l(_bond_m);
if(_bond) {
if (_bond) {
return _bond->rateGatePathNegotiation(now, path);
}
return false; // Default behavior. If there is no bond, we drop these
return false; // Default behavior. If there is no bond, we drop these
}
/**
@ -485,7 +524,7 @@ public:
bool flowHashingSupported()
{
Mutex::Lock _l(_bond_m);
if(_bond) {
if (_bond) {
return _bond->flowHashingSupported();
}
return false;
@ -496,8 +535,7 @@ public:
*
* This does not serialize everything, just non-ephemeral information.
*/
template<unsigned int C>
inline void serializeForCache(Buffer<C> &b) const
template <unsigned int C> inline void serializeForCache(Buffer<C>& b) const
{
b.append((uint8_t)2);
@ -511,22 +549,22 @@ public:
{
Mutex::Lock _l(_paths_m);
unsigned int pc = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
++pc;
} else {
}
else {
break;
}
}
b.append((uint16_t)pc);
for(unsigned int i=0;i<pc;++i) {
for (unsigned int i = 0; i < pc; ++i) {
_paths[i].p->address().serialize(b);
}
}
}
template<unsigned int C>
inline static SharedPtr<Peer> deserializeFromCache(int64_t now,void *tPtr,Buffer<C> &b,const RuntimeEnvironment *renv)
template <unsigned int C> inline static SharedPtr<Peer> deserializeFromCache(int64_t now, void* tPtr, Buffer<C>& b, const RuntimeEnvironment* renv)
{
try {
unsigned int ptr = 0;
@ -535,12 +573,12 @@ public:
}
Identity id;
ptr += id.deserialize(b,ptr);
if (!id) {
ptr += id.deserialize(b, ptr);
if (! id) {
return SharedPtr<Peer>();
}
SharedPtr<Peer> p(new Peer(renv,renv->identity,id));
SharedPtr<Peer> p(new Peer(renv, renv->identity, id));
p->_vProto = b.template at<uint16_t>(ptr);
ptr += 2;
@ -556,20 +594,22 @@ public:
// Paths are fairly ephemeral in the real world in most cases.
const unsigned int tryPathCount = b.template at<uint16_t>(ptr);
ptr += 2;
for(unsigned int i=0;i<tryPathCount;++i) {
for (unsigned int i = 0; i < tryPathCount; ++i) {
InetAddress inaddr;
try {
ptr += inaddr.deserialize(b,ptr);
ptr += inaddr.deserialize(b, ptr);
if (inaddr) {
p->attemptToContactAt(tPtr,-1,inaddr,now,true);
p->attemptToContactAt(tPtr, -1, inaddr, now, true);
}
} catch ( ... ) {
}
catch (...) {
break;
}
}
return p;
} catch ( ... ) {
}
catch (...) {
return SharedPtr<Peer>();
}
}
@ -577,12 +617,16 @@ public:
/**
* @return The bonding policy used to reach this peer
*/
SharedPtr<Bond> bond() { return _bond; }
SharedPtr<Bond> bond()
{
return _bond;
}
/**
* @return The bonding policy used to reach this peer
*/
inline int8_t bondingPolicy() {
inline int8_t bondingPolicy()
{
Mutex::Lock _l(_bond_m);
if (_bond) {
return _bond->policy();
@ -593,7 +637,8 @@ public:
/**
* @return the number of links in this bond which are considered alive
*/
inline uint8_t getNumAliveLinks() {
inline uint8_t getNumAliveLinks()
{
Mutex::Lock _l(_paths_m);
if (_bond) {
return _bond->getNumAliveLinks();
@ -604,7 +649,8 @@ public:
/**
* @return the number of links in this bond
*/
inline uint8_t getNumTotalLinks() {
inline uint8_t getNumTotalLinks()
{
Mutex::Lock _l(_paths_m);
if (_bond) {
return _bond->getNumTotalLinks();
@ -612,31 +658,36 @@ public:
return 0;
}
//inline const AES *aesKeysIfSupported() const
// inline const AES *aesKeysIfSupported() const
//{ return (const AES *)0; }
inline const AES *aesKeysIfSupported() const
{ return (_vProto >= 12) ? _aesKeys : (const AES *)0; }
inline const AES *aesKeys() const
{ return _aesKeys; }
private:
struct _PeerPath
inline const AES* aesKeysIfSupported() const
{
_PeerPath() : lr(0),p(),priority(1) {}
int64_t lr; // time of last valid ZeroTier packet
return (_vProto >= 12) ? _aesKeys : (const AES*)0;
}
inline const AES* aesKeys() const
{
return _aesKeys;
}
private:
struct _PeerPath {
_PeerPath() : lr(0), p(), priority(1)
{
}
int64_t lr; // time of last valid ZeroTier packet
SharedPtr<Path> p;
long priority; // >= 1, higher is better
long priority; // >= 1, higher is better
};
uint8_t _key[ZT_SYMMETRIC_KEY_SIZE];
AES _aesKeys[2];
const RuntimeEnvironment *RR;
const RuntimeEnvironment* RR;
int64_t _lastReceive; // direct or indirect
int64_t _lastNontrivialReceive; // frames, things like netconf, etc.
int64_t _lastReceive; // direct or indirect
int64_t _lastNontrivialReceive; // frames, things like netconf, etc.
int64_t _lastTriedMemorizedPath;
int64_t _lastDirectPathPushSent;
int64_t _lastDirectPathPushReceive;
@ -654,7 +705,7 @@ private:
uint16_t _vMinor;
uint16_t _vRevision;
std::list< std::pair< Path *, int64_t > > _lastTriedPath;
std::list<std::pair<Path*, int64_t> > _lastTriedPath;
Mutex _lastTriedPath_m;
_PeerPath _paths[ZT_MAX_PEER_NETWORK_PATHS];
@ -679,7 +730,7 @@ private:
SharedPtr<Bond> _bond;
#ifndef ZT_NO_PEER_METRICS
prometheus::Histogram<uint64_t> &_peer_latency;
prometheus::Histogram<uint64_t>& _peer_latency;
prometheus::simpleapi::gauge_metric_t _alive_path_count;
prometheus::simpleapi::gauge_metric_t _dead_path_count;
prometheus::simpleapi::counter_metric_t _incoming_packet;
@ -688,15 +739,14 @@ private:
#endif
};
} // namespace ZeroTier
} // 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);
}
template <> inline void swap(ZeroTier::SharedPtr<ZeroTier::Peer>& a, ZeroTier::SharedPtr<ZeroTier::Peer>& b)
{
a.swap(b);
}
} // namespace std
#endif

View file

@ -4,16 +4,17 @@ D. J. Bernstein
Public domain.
*/
#include "Constants.hpp"
#include "Poly1305.hpp"
#include <stdio.h>
#include "Constants.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __WINDOWS__
#pragma warning(disable: 4146)
#pragma warning(disable : 4146)
#endif
namespace ZeroTier {
@ -21,8 +22,8 @@ namespace ZeroTier {
namespace {
typedef struct poly1305_context {
size_t aligner;
unsigned char opaque[136];
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__) || defined(_M_X64))
@ -31,32 +32,42 @@ typedef struct poly1305_context {
// 128-bit implementation for MSC and GCC from Poly1305-donna
#if defined(_MSC_VER)
#include <intrin.h>
#include <intrin.h>
typedef struct uint128_t {
unsigned long long lo;
unsigned long long hi;
} uint128_t;
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 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
#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 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
@ -65,192 +76,228 @@ typedef struct poly1305_context {
/* 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;
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;
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN)
static inline unsigned long long U8TO64(const unsigned char *p)
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));
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));
}
#else
#define U8TO64(p) (*reinterpret_cast<const unsigned long long *>(p))
#define U8TO64(p) (*reinterpret_cast<const unsigned long long*>(p))
#endif
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN)
static inline void U64TO8(unsigned char *p, unsigned long long v)
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;
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;
}
#else
#define U64TO8(p,v) ((*reinterpret_cast<unsigned long long *>(p)) = (v))
#define U64TO8(p, v) ((*reinterpret_cast<unsigned long long*>(p)) = (v))
#endif
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;
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]);
/* 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;
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;
/* 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]);
/* save pad for later */
st->pad[0] = U8TO64(&key[16]);
st->pad[1] = U8TO64(&key[24]);
st->leftover = 0;
st->final = 0;
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;
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];
r0 = st->r[0];
r1 = st->r[1];
r2 = st->r[2];
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
s1 = r1 * (5 << 2);
s2 = r2 * (5 << 2);
s1 = r1 * (5 << 2);
s2 = r2 * (5 << 2);
while (bytes >= poly1305_block_size) {
unsigned long long t0,t1;
while (bytes >= poly1305_block_size) {
unsigned long long t0, t1;
/* h += m[i] */
t0 = U8TO64(&m[0]);
t1 = U8TO64(&m[8]);
/* 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;
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);
/* 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;
/* (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;
}
m += poly1305_block_size;
bytes -= poly1305_block_size;
}
st->h[0] = h0;
st->h[1] = h1;
st->h[2] = h2;
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;
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);
}
/* 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];
/* 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;
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);
/* 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;
/* 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];
/* 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;
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));
/* mac = h % (2^128) */
h0 = ((h0) | (h1 << 44));
h1 = ((h1 >> 20) | (h2 << 24));
U64TO8(&mac[0], h0);
U64TO8(&mac[8], h1);
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;
/* 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;
}
//////////////////////////////////////////////////////////////////////////////
@ -264,262 +311,291 @@ static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[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;
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));
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 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;
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;
/* 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;
/* 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]);
/* 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;
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;
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];
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;
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];
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;
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);
/* 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;
/* (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;
}
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;
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;
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);
}
/* 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];
/* 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;
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);
/* 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;
/* 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;
/* 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;
/* 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);
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;
/* 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
#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)
static inline void poly1305_update(poly1305_context* ctx, const unsigned char* m, size_t bytes)
{
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));
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;
}
}
} // namespace ZeroTier
} // anonymous namespace
void Poly1305::compute(void* auth, const void* data, unsigned int len, const void* key)
{
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

View file

@ -30,9 +30,8 @@ namespace ZeroTier {
* 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:
class Poly1305 {
public:
/**
* Compute a one-time authentication code
*
@ -41,9 +40,9 @@ public:
* @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);
static void compute(void* auth, const void* data, unsigned int len, const void* key);
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -12,32 +12,34 @@
/****/
#include "Revocation.hpp"
#include "RuntimeEnvironment.hpp"
#include "Identity.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier {
int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const
int Revocation::verify(const RuntimeEnvironment* RR, void* tPtr) const
{
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) {
if ((! _signedBy) || (_signedBy != Network::controllerFor(_networkId))) {
return -1;
}
const Identity id(RR->topology->getIdentity(tPtr,_signedBy));
if (!id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy);
const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (! id) {
RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1;
}
try {
Buffer<sizeof(Revocation) + 64> tmp;
this->serialize(tmp,true);
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
} catch ( ... ) {
this->serialize(tmp, true);
return (id.verify(tmp.data(), tmp.size(), _signature) ? 0 : -1);
}
catch (...) {
return -1;
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,19 +14,19 @@
#ifndef ZT_REVOCATION_HPP
#define ZT_REVOCATION_HPP
#include "../include/ZeroTierOne.h"
#include "Address.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Credential.hpp"
#include "Address.hpp"
#include "C25519.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include "Identity.hpp"
/**
* Flag: fast propagation via rumor mill algorithm
@ -40,22 +40,16 @@ class RuntimeEnvironment;
/**
* Revocation certificate to instantaneously revoke a COM, capability, or tag
*/
class Revocation : public Credential
{
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
Revocation() :
_id(0),
_credentialId(0),
_networkId(0),
_threshold(0),
_flags(0),
_target(),
_signedBy(),
_type(Credential::CREDENTIAL_TYPE_NULL)
class Revocation : public Credential {
public:
static inline Credential::Type credentialType()
{
memset(_signature.data,0,sizeof(_signature.data));
return Credential::CREDENTIAL_TYPE_REVOCATION;
}
Revocation() : _id(0), _credentialId(0), _networkId(0), _threshold(0), _flags(0), _target(), _signedBy(), _type(Credential::CREDENTIAL_TYPE_NULL)
{
memset(_signature.data, 0, sizeof(_signature.data));
}
/**
@ -67,40 +61,64 @@ public:
* @param tgt Target node whose credential(s) are being revoked
* @param ct Credential type being revoked
*/
Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const int64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) :
_id(i),
_credentialId(cid),
_networkId(nwid),
_threshold(thr),
_flags(fl),
_target(tgt),
_signedBy(),
_type(ct)
Revocation(const uint32_t i, const uint64_t nwid, const uint32_t cid, const int64_t thr, const uint64_t fl, const Address& tgt, const Credential::Type ct)
: _id(i)
, _credentialId(cid)
, _networkId(nwid)
, _threshold(thr)
, _flags(fl)
, _target(tgt)
, _signedBy()
, _type(ct)
{
memset(_signature.data,0,sizeof(_signature.data));
memset(_signature.data, 0, sizeof(_signature.data));
}
inline uint32_t id() const { return _id; }
inline uint32_t credentialId() const { return _credentialId; }
inline uint64_t networkId() const { return _networkId; }
inline int64_t threshold() const { return _threshold; }
inline const Address &target() const { return _target; }
inline const Address &signer() const { return _signedBy; }
inline Credential::Type type() const { return _type; }
inline uint32_t id() const
{
return _id;
}
inline uint32_t credentialId() const
{
return _credentialId;
}
inline uint64_t networkId() const
{
return _networkId;
}
inline int64_t threshold() const
{
return _threshold;
}
inline const Address& target() const
{
return _target;
}
inline const Address& signer() const
{
return _signedBy;
}
inline Credential::Type type() const
{
return _type;
}
inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
inline bool fastPropagate() const
{
return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0);
}
/**
* @param signer Signing identity, must have private key
* @return True if signature was successful
*/
inline bool sign(const Identity &signer)
inline bool sign(const Identity& signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(Revocation) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signature = signer.sign(tmp.data(),tmp.size());
this->serialize(tmp, true);
_signature = signer.sign(tmp.data(), tmp.size());
return true;
}
return false;
@ -113,19 +131,18 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain
*/
int verify(const RuntimeEnvironment *RR,void *tPtr) const;
int verify(const RuntimeEnvironment* RR, void* tPtr) const;
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
{
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
b.append(_id);
b.append(_networkId);
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
b.append(_credentialId);
b.append(_threshold);
b.append(_flags);
@ -133,10 +150,10 @@ public:
_signedBy.appendTo(b);
b.append((uint8_t)_type);
if (!forSign) {
b.append((uint8_t)1); // 1 == Ed25519 signature
if (! forSign) {
b.append((uint8_t)1); // 1 == Ed25519 signature
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN);
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
b.append(_signature.data, ZT_C25519_SIGNATURE_LEN);
}
// This is the size of any additional fields, currently 0.
@ -147,40 +164,41 @@ public:
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
*this = Revocation();
unsigned int p = startAt;
p += 4; // 4 bytes, currently unused
p += 4; // 4 bytes, currently unused
_id = b.template at<uint32_t>(p);
p += 4;
_networkId = b.template at<uint64_t>(p);
p += 8;
p += 4; // 4 bytes, currently unused
p += 4; // 4 bytes, currently unused
_credentialId = b.template at<uint32_t>(p);
p += 4;
_threshold = (int64_t)b.template at<uint64_t>(p);
p += 8;
_flags = b.template at<uint64_t>(p);
p += 8;
_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
_target.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
_signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
_type = (Credential::Type)b[p++];
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) == ZT_C25519_SIGNATURE_LEN) {
p += 2;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
memcpy(_signature.data, b.field(p, ZT_C25519_SIGNATURE_LEN), ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else {
}
else {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
}
} else {
}
else {
p += 2 + b.template at<uint16_t>(p);
}
@ -192,7 +210,7 @@ public:
return (p - startAt);
}
private:
private:
uint32_t _id;
uint32_t _credentialId;
uint64_t _networkId;
@ -204,6 +222,6 @@ private:
C25519::Signature _signature;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -14,12 +14,12 @@
#ifndef ZT_RINGBUFFER_H
#define ZT_RINGBUFFER_H
#include <typeinfo>
#include <cstdint>
#include <stdlib.h>
#include <memory.h>
#include <algorithm>
#include <cstdint>
#include <math.h>
#include <memory.h>
#include <stdlib.h>
#include <typeinfo>
namespace ZeroTier {
@ -34,28 +34,23 @@ namespace ZeroTier {
* to reduce the complexity of code needed to interact with this type of buffer.
*/
template <class T,size_t S>
class RingBuffer
{
private:
template <class T, size_t S> class RingBuffer {
private:
T buf[S];
size_t begin;
size_t end;
bool wrap;
public:
RingBuffer() :
begin(0),
end(0),
wrap(false)
public:
RingBuffer() : begin(0), end(0), wrap(false)
{
memset(buf,0,sizeof(T)*S);
memset(buf, 0, sizeof(T) * S);
}
/**
* @return A pointer to the underlying buffer
*/
inline T *get_buf()
inline T* get_buf()
{
return buf + begin;
}
@ -87,7 +82,10 @@ public:
* Fast erase, O(1).
* Merely reset the buffer pointer, doesn't erase contents
*/
inline void reset() { consume(count()); }
inline void reset()
{
consume(count());
}
/**
* adjust buffer index pointer as if we copied data out
@ -116,7 +114,7 @@ public:
* @param data Buffer that is to be written to the ring
* @param n Number of elements to write to the buffer
*/
inline size_t write(const T * data, size_t n)
inline size_t write(const T* data, size_t n)
{
n = std::min(n, getFree());
if (n == 0) {
@ -157,14 +155,17 @@ public:
/**
* @return The most recently pushed element on the buffer
*/
inline T get_most_recent() { return *(buf + end); }
inline T get_most_recent()
{
return *(buf + end);
}
/**
* @param dest Destination buffer
* @param n Size (in terms of number of elements) of the destination buffer
* @return Number of elements read from the buffer
*/
inline size_t read(T *dest,size_t n)
inline size_t read(T* dest, size_t n)
{
n = std::min(n, count());
if (n == 0) {
@ -193,9 +194,11 @@ public:
{
if (end == begin) {
return wrap ? S : 0;
} else if (end > begin) {
}
else if (end > begin) {
return end - begin;
} else {
}
else {
return S + end - begin;
}
}
@ -203,7 +206,10 @@ public:
/**
* @return The number of slots that are unused in the buffer
*/
inline size_t getFree() { return S - count(); }
inline size_t getFree()
{
return S - count();
}
/**
* @return The arithmetic mean of the contents of the buffer
@ -213,7 +219,7 @@ public:
size_t iterator = begin;
float subtotal = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
subtotal += (float)*(buf + iterator);
}
@ -229,7 +235,7 @@ public:
size_t iterator = begin;
float subtotal = 0;
size_t curr_cnt = count();
for (size_t i=0; i<n; i++) {
for (size_t i = 0; i < n; i++) {
iterator = (iterator + S - 1) % curr_cnt;
subtotal += (float)*(buf + iterator);
}
@ -244,7 +250,7 @@ public:
size_t iterator = begin;
float total = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
total += (float)*(buf + iterator);
}
@ -254,7 +260,10 @@ public:
/**
* @return The sample standard deviation of element values
*/
inline float stddev() { return sqrt(variance()); }
inline float stddev()
{
return sqrt(variance());
}
/**
* @return The variance of element values
@ -265,10 +274,10 @@ public:
float cached_mean = mean();
size_t curr_cnt = count();
T sum_of_squared_deviations = 0;
for (size_t i=0; i<curr_cnt; i++) {
for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
float deviation = (buf[i] - cached_mean);
sum_of_squared_deviations += (T)(deviation*deviation);
sum_of_squared_deviations += (T)(deviation * deviation);
}
float variance = (float)sum_of_squared_deviations / (float)(S - 1);
return variance;
@ -282,7 +291,7 @@ public:
size_t iterator = begin;
size_t zeros = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
if (*(buf + iterator) == 0) {
zeros++;
@ -300,7 +309,7 @@ public:
size_t iterator = begin;
size_t cnt = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
if (*(buf + iterator) == value) {
cnt++;
@ -329,6 +338,6 @@ public:
*/
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -14,11 +14,11 @@
#ifndef ZT_RUNTIMEENVIRONMENT_HPP
#define ZT_RUNTIMEENVIRONMENT_HPP
#include <string.h>
#include "Constants.hpp"
#include "Utils.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include <string.h>
namespace ZeroTier {
@ -36,17 +36,9 @@ class PacketMultiplexer;
/**
* Holds global state for an instance of ZeroTier::Node
*/
class RuntimeEnvironment
{
public:
RuntimeEnvironment(Node *n) :
node(n)
,localNetworkController((NetworkController *)0)
,rtmem((void *)0)
,sw((Switch *)0)
,mc((Multicaster *)0)
,topology((Topology *)0)
,sa((SelfAwareness *)0)
class RuntimeEnvironment {
public:
RuntimeEnvironment(Node* n) : node(n), localNetworkController((NetworkController*)0), rtmem((void*)0), sw((Switch*)0), mc((Multicaster*)0), topology((Topology*)0), sa((SelfAwareness*)0)
{
publicIdentityStr[0] = (char)0;
secretIdentityStr[0] = (char)0;
@ -54,17 +46,17 @@ public:
~RuntimeEnvironment()
{
Utils::burn(secretIdentityStr,sizeof(secretIdentityStr));
Utils::burn(secretIdentityStr, sizeof(secretIdentityStr));
}
// Node instance that owns this RuntimeEnvironment
Node *const node;
Node* const node;
// This is set externally to an instance of this base class
NetworkController *localNetworkController;
NetworkController* localNetworkController;
// Memory actually occupied by Trace, Switch, etc.
void *rtmem;
void* rtmem;
/* Order matters a bit here. These are constructed in this order
* and then deleted in the opposite order on Node exit. The order ensures
@ -72,13 +64,13 @@ public:
*
* These are constant and never null after startup unless indicated. */
Trace *t;
Switch *sw;
Multicaster *mc;
Topology *topology;
SelfAwareness *sa;
Bond *bc;
PacketMultiplexer *pm;
Trace* t;
Switch* sw;
Multicaster* mc;
Topology* topology;
SelfAwareness* sa;
Bond* bc;
PacketMultiplexer* pm;
// This node's identity and string representations thereof
Identity identity;
@ -86,6 +78,6 @@ public:
char secretIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH];
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -1,10 +1,11 @@
// This code is public domain, taken from a PD crypto source file on GitHub.
#include <algorithm>
#include "SHA512.hpp"
#include "Utils.hpp"
#include <algorithm>
namespace ZeroTier {
#ifndef ZT_HAVE_NATIVE_SHA512
@ -12,48 +13,35 @@ namespace ZeroTier {
namespace {
struct sha512_state {
uint64_t length,state[8];
uint64_t length, state[8];
unsigned long curlen;
uint8_t buf[128];
};
static const uint64_t K[80] = {
0x428a2f98d728ae22ULL,0x7137449123ef65cdULL,0xb5c0fbcfec4d3b2fULL,0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL,0x59f111f1b605d019ULL,0x923f82a4af194f9bULL,0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL,0x12835b0145706fbeULL,0x243185be4ee4b28cULL,0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL,0x80deb1fe3b1696b1ULL,0x9bdc06a725c71235ULL,0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL,0xefbe4786384f25e3ULL,0x0fc19dc68b8cd5b5ULL,0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL,0x4a7484aa6ea6e483ULL,0x5cb0a9dcbd41fbd4ULL,0x76f988da831153b5ULL,
0x983e5152ee66dfabULL,0xa831c66d2db43210ULL,0xb00327c898fb213fULL,0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL,0xd5a79147930aa725ULL,0x06ca6351e003826fULL,0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL,0x2e1b21385c26c926ULL,0x4d2c6dfc5ac42aedULL,0x53380d139d95b3dfULL,
0x650a73548baf63deULL,0x766a0abb3c77b2a8ULL,0x81c2c92e47edaee6ULL,0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL,0xa81a664bbc423001ULL,0xc24b8b70d0f89791ULL,0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL,0xd69906245565a910ULL,0xf40e35855771202aULL,0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL,0x1e376c085141ab53ULL,0x2748774cdf8eeb99ULL,0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL,0x4ed8aa4ae3418acbULL,0x5b9cca4f7763e373ULL,0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL,0x78a5636f43172f60ULL,0x84c87814a1f0ab72ULL,0x8cc702081a6439ecULL,
0x90befffa23631e28ULL,0xa4506cebde82bde9ULL,0xbef9a3f7b2c67915ULL,0xc67178f2e372532bULL,
0xca273eceea26619cULL,0xd186b8c721c0c207ULL,0xeada7dd6cde0eb1eULL,0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL,0x0a637dc5a2c898a6ULL,0x113f9804bef90daeULL,0x1b710b35131c471bULL,
0x28db77f523047d84ULL,0x32caab7b40c72493ULL,0x3c9ebe0a15c9bebcULL,0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL,0x597f299cfc657e2aULL,0x5fcb6fab3ad6faecULL,0x6c44198c4a475817ULL
};
static const uint64_t K[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL };
#define STORE64H(x, y) Utils::storeBigEndian<uint64_t>(y,x)
#define LOAD64H(x, y) x = Utils::loadBigEndian<uint64_t>(y)
#define ROL64c(x,y) (((x)<<(y)) | ((x)>>(64-(y))))
#define ROR64c(x,y) (((x)>>(y)) | ((x)<<(64-(y))))
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n)
#define R(x, n) ((x)>>(n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
#define STORE64H(x, y) Utils::storeBigEndian<uint64_t>(y, x)
#define LOAD64H(x, y) x = Utils::loadBigEndian<uint64_t>(y)
#define ROL64c(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#define ROR64c(x, y) (((x) >> (y)) | ((x) << (64 - (y))))
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n)
#define R(x, n) ((x) >> (n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
static ZT_INLINE void sha512_compress(sha512_state* const md, uint8_t* const buf)
{
uint64_t S[8], W[80], t0, t1;
int i;
@ -62,27 +50,27 @@ static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
S[i] = md->state[i];
}
for (i = 0; i < 16; i++) {
LOAD64H(W[i], buf + (8*i));
LOAD64H(W[i], buf + (8 * i));
}
for (i = 16; i < 80; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
#define RND(a,b,c,d,e,f,g,h,i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
#define RND(a, b, c, d, e, f, g, h, i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
for (i = 0; i < 80; i += 8) {
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6);
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], i + 7);
}
for (i = 0; i < 8; i++) {
@ -90,7 +78,7 @@ static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
}
}
static ZT_INLINE void sha384_init(sha512_state *const md)
static ZT_INLINE void sha384_init(sha512_state* const md)
{
md->curlen = 0;
md->length = 0;
@ -104,7 +92,7 @@ static ZT_INLINE void sha384_init(sha512_state *const md)
md->state[7] = 0x47b5481dbefa4fa4ULL;
}
static ZT_INLINE void sha512_init(sha512_state *const md)
static ZT_INLINE void sha512_init(sha512_state* const md)
{
md->curlen = 0;
md->length = 0;
@ -118,30 +106,31 @@ static ZT_INLINE void sha512_init(sha512_state *const md)
md->state[7] = 0x5be0cd19137e2179ULL;
}
static void sha512_process(sha512_state *const md,const uint8_t *in,unsigned long inlen)
static void sha512_process(sha512_state* const md, const uint8_t* in, unsigned long inlen)
{
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 128) {
sha512_compress(md,(uint8_t *)in);
md->length += 128 * 8;
in += 128;
inlen -= 128;
} else {
unsigned long n = std::min(inlen,(128 - md->curlen));
Utils::copy(md->buf + md->curlen,in,n);
sha512_compress(md, (uint8_t*)in);
md->length += 128 * 8;
in += 128;
inlen -= 128;
}
else {
unsigned long n = std::min(inlen, (128 - md->curlen));
Utils::copy(md->buf + md->curlen, in, n);
md->curlen += n;
in += n;
inlen -= n;
in += n;
inlen -= n;
if (md->curlen == 128) {
sha512_compress(md,md->buf);
md->length += 8*128;
sha512_compress(md, md->buf);
md->length += 8 * 128;
md->curlen = 0;
}
}
}
}
static ZT_INLINE void sha512_done(sha512_state *const md,uint8_t *out)
static ZT_INLINE void sha512_done(sha512_state* const md, uint8_t* out)
{
int i;
@ -160,58 +149,58 @@ static ZT_INLINE void sha512_done(sha512_state *const md,uint8_t *out)
md->buf[md->curlen++] = (uint8_t)0;
}
STORE64H(md->length, md->buf+120);
STORE64H(md->length, md->buf + 120);
sha512_compress(md, md->buf);
for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out+(8*i));
STORE64H(md->state[i], out + (8 * i));
}
}
} // anonymous namespace
} // anonymous namespace
void SHA512(void *digest,const void *data,unsigned int len)
void SHA512(void* digest, const void* data, unsigned int len)
{
sha512_state state;
sha512_init(&state);
sha512_process(&state,(uint8_t *)data,(unsigned long)len);
sha512_done(&state,(uint8_t *)digest);
sha512_process(&state, (uint8_t*)data, (unsigned long)len);
sha512_done(&state, (uint8_t*)digest);
}
void SHA384(void *digest,const void *data,unsigned int len)
void SHA384(void* digest, const void* data, unsigned int len)
{
uint8_t tmp[64];
sha512_state state;
sha384_init(&state);
sha512_process(&state,(uint8_t *)data,(unsigned long)len);
sha512_done(&state,tmp);
Utils::copy<48>(digest,tmp);
sha512_process(&state, (uint8_t*)data, (unsigned long)len);
sha512_done(&state, tmp);
Utils::copy<48>(digest, tmp);
}
void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1)
void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1)
{
uint8_t tmp[64];
sha512_state state;
sha384_init(&state);
sha512_process(&state,(uint8_t *)data0,(unsigned long)len0);
sha512_process(&state,(uint8_t *)data1,(unsigned long)len1);
sha512_done(&state,tmp);
Utils::copy<48>(digest,tmp);
sha512_process(&state, (uint8_t*)data0, (unsigned long)len0);
sha512_process(&state, (uint8_t*)data1, (unsigned long)len1);
sha512_done(&state, tmp);
Utils::copy<48>(digest, tmp);
}
#endif // !ZT_HAVE_NATIVE_SHA512
#endif // !ZT_HAVE_NATIVE_SHA512
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const unsigned int msglen,uint8_t mac[48])
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, const unsigned int msglen, uint8_t mac[48])
{
uint64_t kInPadded[16]; // input padded key
uint64_t outer[22]; // output padded key | H(input padded key | msg)
uint64_t kInPadded[16]; // input padded key
uint64_t outer[22]; // output padded key | H(input padded key | msg)
const uint64_t k0 = Utils::loadMachineEndian< uint64_t >(key);
const uint64_t k1 = Utils::loadMachineEndian< uint64_t >(key + 8);
const uint64_t k2 = Utils::loadMachineEndian< uint64_t >(key + 16);
const uint64_t k3 = Utils::loadMachineEndian< uint64_t >(key + 24);
const uint64_t k4 = Utils::loadMachineEndian< uint64_t >(key + 32);
const uint64_t k5 = Utils::loadMachineEndian< uint64_t >(key + 40);
const uint64_t k0 = Utils::loadMachineEndian<uint64_t>(key);
const uint64_t k1 = Utils::loadMachineEndian<uint64_t>(key + 8);
const uint64_t k2 = Utils::loadMachineEndian<uint64_t>(key + 16);
const uint64_t k3 = Utils::loadMachineEndian<uint64_t>(key + 24);
const uint64_t k4 = Utils::loadMachineEndian<uint64_t>(key + 32);
const uint64_t k5 = Utils::loadMachineEndian<uint64_t>(key + 40);
const uint64_t ipad = 0x3636363636363636ULL;
kInPadded[0] = k0 ^ ipad;
@ -250,18 +239,18 @@ void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const u
outer[15] = opad;
// H(output padded key | H(input padded key | msg))
SHA384(reinterpret_cast<uint8_t *>(outer) + 128,kInPadded,128,msg,msglen);
SHA384(mac,outer,176);
SHA384(reinterpret_cast<uint8_t*>(outer) + 128, kInPadded, 128, msg, msglen);
SHA384(mac, outer, 176);
}
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,const char context,const uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE])
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const char label, const char context, const uint32_t iter, uint8_t out[ZT_SYMMETRIC_KEY_SIZE])
{
uint8_t kbkdfMsg[13];
Utils::storeBigEndian<uint32_t>(kbkdfMsg,(uint32_t)iter);
Utils::storeBigEndian<uint32_t>(kbkdfMsg, (uint32_t)iter);
kbkdfMsg[4] = (uint8_t)'Z';
kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific
kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific
kbkdfMsg[6] = (uint8_t)label;
kbkdfMsg[7] = 0;
@ -273,13 +262,15 @@ void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,c
kbkdfMsg[11] = 0x01;
kbkdfMsg[12] = 0x80;
static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE,"sizeof(out) != ZT_SHA384_DIGEST_SIZE");
HMACSHA384(key,&kbkdfMsg,sizeof(kbkdfMsg),out);
static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE, "sizeof(out) != ZT_SHA384_DIGEST_SIZE");
HMACSHA384(key, &kbkdfMsg, sizeof(kbkdfMsg), out);
}
} // namespace ZeroTier
} // namespace ZeroTier
// Internally re-export to included C code, which includes some fast crypto code ported in on some platforms.
// This eliminates the need to link against a third party SHA512() from this code
extern "C" void ZT_sha512internal(void *digest,const void *data,unsigned int len)
{ ZeroTier::SHA512(digest,data,len); }
extern "C" void ZT_sha512internal(void* digest, const void* data, unsigned int len)
{
ZeroTier::SHA512(digest, data, len);
}

View file

@ -22,8 +22,8 @@
#define ZT_SHA512_DIGEST_SIZE 64
#define ZT_SHA384_DIGEST_SIZE 48
#define ZT_SHA512_BLOCK_SIZE 128
#define ZT_SHA384_BLOCK_SIZE 128
#define ZT_SHA512_BLOCK_SIZE 128
#define ZT_SHA384_BLOCK_SIZE 128
#define ZT_HMACSHA384_LEN 48
@ -32,34 +32,34 @@ namespace ZeroTier {
// SHA384 and SHA512 are actually in the standard libraries on MacOS and iOS
#ifdef __APPLE__
#define ZT_HAVE_NATIVE_SHA512 1
static ZT_INLINE void SHA512(void *digest,const void *data,unsigned int len)
static ZT_INLINE void SHA512(void* digest, const void* data, unsigned int len)
{
CC_SHA512_CTX ctx;
CC_SHA512_Init(&ctx);
CC_SHA512_Update(&ctx,data,len);
CC_SHA512_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
CC_SHA512_Update(&ctx, data, len);
CC_SHA512_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
}
static ZT_INLINE void SHA384(void *digest,const void *data,unsigned int len)
static ZT_INLINE void SHA384(void* digest, const void* data, unsigned int len)
{
CC_SHA512_CTX ctx;
CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx,data,len);
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
CC_SHA384_Update(&ctx, data, len);
CC_SHA384_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
}
static ZT_INLINE void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1)
static ZT_INLINE void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1)
{
CC_SHA512_CTX ctx;
CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx,data0,len0);
CC_SHA384_Update(&ctx,data1,len1);
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
CC_SHA384_Update(&ctx, data0, len0);
CC_SHA384_Update(&ctx, data1, len1);
CC_SHA384_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
}
#endif
#ifndef ZT_HAVE_NATIVE_SHA512
void SHA512(void *digest,const void *data,unsigned int len);
void SHA384(void *digest,const void *data,unsigned int len);
void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1);
void SHA512(void* digest, const void* data, unsigned int len);
void SHA384(void* digest, const void* data, unsigned int len);
void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1);
#endif
/**
@ -70,7 +70,7 @@ void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,u
* @param msglen Length of message
* @param mac Buffer to fill with result
*/
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigned int msglen,uint8_t mac[48]);
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, unsigned int msglen, uint8_t mac[48]);
/**
* Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF
@ -81,8 +81,8 @@ void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigne
* @param iter Key iteration for generation of multiple keys for the same label/context
* @param out Output to receive derived key
*/
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],char label,char context,uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE]);
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], char label, char context, uint32_t iter, uint8_t out[ZT_SYMMETRIC_KEY_SIZE]);
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -7,32 +7,36 @@
#ifndef ZT_SALSA20_HPP
#define ZT_SALSA20_HPP
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "Constants.hpp"
#include "Utils.hpp"
#if (!defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || (defined(__WINDOWS__) && !defined(__MINGW32__) && !defined(_M_ARM64)))
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if (! defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || (defined(__WINDOWS__) && ! defined(__MINGW32__) && ! defined(_M_ARM64)))
#define ZT_SALSA20_SSE 1
#endif
#ifdef ZT_SALSA20_SSE
#include <emmintrin.h>
#endif // ZT_SALSA20_SSE
#endif // ZT_SALSA20_SSE
namespace ZeroTier {
/**
* Salsa20 stream cipher
*/
class Salsa20
{
public:
Salsa20() {}
~Salsa20() { Utils::burn(&_state,sizeof(_state)); }
class Salsa20 {
public:
Salsa20()
{
}
~Salsa20()
{
Utils::burn(&_state, sizeof(_state));
}
/**
* XOR d with s
@ -45,48 +49,48 @@ public:
* @param s Source bytes to XOR with destination
* @param len Length of s and d
*/
static inline void memxor(uint8_t *d,const uint8_t *s,unsigned int len)
static inline void memxor(uint8_t* d, const uint8_t* s, unsigned int len)
{
#ifdef ZT_SALSA20_SSE
while (len >= 128) {
__m128i s0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s));
__m128i s1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 16));
__m128i s2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 32));
__m128i s3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 48));
__m128i s4 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 64));
__m128i s5 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 80));
__m128i s6 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 96));
__m128i s7 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 112));
__m128i d0 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d));
__m128i d1 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 16));
__m128i d2 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 32));
__m128i d3 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 48));
__m128i d4 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 64));
__m128i d5 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 80));
__m128i d6 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 96));
__m128i d7 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 112));
d0 = _mm_xor_si128(d0,s0);
d1 = _mm_xor_si128(d1,s1);
d2 = _mm_xor_si128(d2,s2);
d3 = _mm_xor_si128(d3,s3);
d4 = _mm_xor_si128(d4,s4);
d5 = _mm_xor_si128(d5,s5);
d6 = _mm_xor_si128(d6,s6);
d7 = _mm_xor_si128(d7,s7);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d),d0);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 16),d1);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 32),d2);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 48),d3);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 64),d4);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 80),d5);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 96),d6);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 112),d7);
__m128i s0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s));
__m128i s1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 16));
__m128i s2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 32));
__m128i s3 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 48));
__m128i s4 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 64));
__m128i s5 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 80));
__m128i s6 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 96));
__m128i s7 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 112));
__m128i d0 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d));
__m128i d1 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 16));
__m128i d2 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 32));
__m128i d3 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 48));
__m128i d4 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 64));
__m128i d5 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 80));
__m128i d6 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 96));
__m128i d7 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 112));
d0 = _mm_xor_si128(d0, s0);
d1 = _mm_xor_si128(d1, s1);
d2 = _mm_xor_si128(d2, s2);
d3 = _mm_xor_si128(d3, s3);
d4 = _mm_xor_si128(d4, s4);
d5 = _mm_xor_si128(d5, s5);
d6 = _mm_xor_si128(d6, s6);
d7 = _mm_xor_si128(d7, s7);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d), d0);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 16), d1);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 32), d2);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 48), d3);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 64), d4);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 80), d5);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 96), d6);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 112), d7);
s += 128;
d += 128;
len -= 128;
}
while (len >= 16) {
_mm_storeu_si128(reinterpret_cast<__m128i *>(d),_mm_xor_si128(_mm_loadu_si128(reinterpret_cast<__m128i *>(d)),_mm_loadu_si128(reinterpret_cast<const __m128i *>(s))));
_mm_storeu_si128(reinterpret_cast<__m128i*>(d), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<__m128i*>(d)), _mm_loadu_si128(reinterpret_cast<const __m128i*>(s))));
s += 16;
d += 16;
len -= 16;
@ -94,10 +98,10 @@ public:
#else
#ifndef ZT_NO_TYPE_PUNNING
while (len >= 16) {
(*reinterpret_cast<uint64_t *>(d)) ^= (*reinterpret_cast<const uint64_t *>(s));
(*reinterpret_cast<uint64_t*>(d)) ^= (*reinterpret_cast<const uint64_t*>(s));
s += 8;
d += 8;
(*reinterpret_cast<uint64_t *>(d)) ^= (*reinterpret_cast<const uint64_t *>(s));
(*reinterpret_cast<uint64_t*>(d)) ^= (*reinterpret_cast<const uint64_t*>(s));
s += 8;
d += 8;
len -= 16;
@ -114,9 +118,9 @@ public:
* @param key 256-bit (32 byte) key
* @param iv 64-bit initialization vector
*/
Salsa20(const void *key,const void *iv)
Salsa20(const void* key, const void* iv)
{
init(key,iv);
init(key, iv);
}
/**
@ -125,7 +129,7 @@ public:
* @param key Key bits
* @param iv 64-bit initialization vector
*/
void init(const void *key,const void *iv);
void init(const void* key, const void* iv);
/**
* Encrypt/decrypt data using Salsa20/12
@ -134,7 +138,7 @@ public:
* @param out Output buffer
* @param bytes Length of data
*/
void crypt12(const void *in,void *out,unsigned int bytes);
void crypt12(const void* in, void* out, unsigned int bytes);
/**
* Encrypt/decrypt data using Salsa20/20
@ -143,17 +147,17 @@ public:
* @param out Output buffer
* @param bytes Length of data
*/
void crypt20(const void *in,void *out,unsigned int bytes);
void crypt20(const void* in, void* out, unsigned int bytes);
private:
private:
union {
#ifdef ZT_SALSA20_SSE
__m128i v[4];
#endif // ZT_SALSA20_SSE
#endif // ZT_SALSA20_SSE
uint32_t i[16];
} _state;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,66 +11,64 @@
*/
/****/
#include "SelfAwareness.hpp"
#include "Constants.hpp"
#include "Node.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
#include "Trace.hpp"
#include <set>
#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"
#include "Trace.hpp"
// Entry timeout -- make it fairly long since this is just to prevent stale buildup
#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000
namespace ZeroTier {
class _ResetWithinScope
{
public:
_ResetWithinScope(void *tPtr,int64_t now,int inetAddressFamily,InetAddress::IpScope scope) :
_now(now),
_tPtr(tPtr),
_family(inetAddressFamily),
_scope(scope) {}
class _ResetWithinScope {
public:
_ResetWithinScope(void* tPtr, int64_t now, int inetAddressFamily, InetAddress::IpScope scope) : _now(now), _tPtr(tPtr), _family(inetAddressFamily), _scope(scope)
{
}
inline void operator()(Topology &t,const SharedPtr<Peer> &p) { p->resetWithinScope(_tPtr,_scope,_family,_now); }
inline void operator()(Topology& t, const SharedPtr<Peer>& p)
{
p->resetWithinScope(_tPtr, _scope, _family, _now);
}
private:
private:
uint64_t _now;
void *_tPtr;
void* _tPtr;
int _family;
InetAddress::IpScope _scope;
};
SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) :
RR(renv),
_phy(128)
SelfAwareness::SelfAwareness(const RuntimeEnvironment* renv) : RR(renv), _phy(128)
{
}
void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now)
void SelfAwareness::iam(void* tPtr, const Address& reporter, const int64_t receivedOnLocalSocket, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, bool trusted, int64_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)) {
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,receivedOnLocalSocket,reporterPhysicalAddress,scope)];
PhySurfaceEntry& entry = _phy[PhySurfaceKey(reporter, receivedOnLocalSocket, reporterPhysicalAddress, scope)];
if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) {
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
RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,myPhysicalAddress,scope);
RR->t->resettingPathsInScope(tPtr, reporter, reporterPhysicalAddress, myPhysicalAddress, scope);
entry.mySurface = myPhysicalAddress;
entry.ts = now;
@ -80,20 +78,21 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
// 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)) {
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 and address family
_ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope);
RR->topology->eachPeer<_ResetWithinScope &>(rset);
} else {
_ResetWithinScope rset(tPtr, now, myPhysicalAddress.ss_family, (InetAddress::IpScope)scope);
RR->topology->eachPeer<_ResetWithinScope&>(rset);
}
else {
// Otherwise just update DB to use to determine external surface info
entry.mySurface = myPhysicalAddress;
entry.ts = now;
@ -105,10 +104,10 @@ std::vector<InetAddress> SelfAwareness::whoami()
{
std::vector<InetAddress> surfaceAddresses;
Mutex::Lock _l(_phy_m);
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
while (i.next(k,e)) {
Hashtable<PhySurfaceKey, PhySurfaceEntry>::Iterator i(_phy);
PhySurfaceKey* k = (PhySurfaceKey*)0;
PhySurfaceEntry* e = (PhySurfaceEntry*)0;
while (i.next(k, e)) {
if (std::find(surfaceAddresses.begin(), surfaceAddresses.end(), e->mySurface) == surfaceAddresses.end()) {
surfaceAddresses.push_back(e->mySurface);
}
@ -119,14 +118,14 @@ std::vector<InetAddress> SelfAwareness::whoami()
void SelfAwareness::clean(int64_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)) {
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);
}
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,10 +14,10 @@
#ifndef ZT_SELFAWARENESS_HPP
#define ZT_SELFAWARENESS_HPP
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "Hashtable.hpp"
#include "Address.hpp"
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "InetAddress.hpp"
#include "Mutex.hpp"
namespace ZeroTier {
@ -27,10 +27,9 @@ class RuntimeEnvironment;
/**
* Tracks changes to this peer's real world addresses
*/
class SelfAwareness
{
public:
SelfAwareness(const RuntimeEnvironment *renv);
class SelfAwareness {
public:
SelfAwareness(const RuntimeEnvironment* renv);
/**
* Called when a trusted remote peer informs us of our external network address
@ -42,7 +41,7 @@ public:
* @param trusted True if this peer is trusted as an authority to inform us of external address changes
* @param now Current time
*/
void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now);
void iam(void* tPtr, const Address& reporter, const int64_t receivedOnLocalSocket, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, bool trusted, int64_t now);
/**
* Return all known external surface addresses reported by peers
@ -58,36 +57,48 @@ public:
*/
void clean(int64_t now);
private:
struct PhySurfaceKey
{
private:
struct PhySurfaceKey {
Address reporter;
int64_t receivedOnLocalSocket;
InetAddress reporterPhysicalAddress;
InetAddress::IpScope scope;
PhySurfaceKey() : reporter(),scope(InetAddress::IP_SCOPE_NONE) {}
PhySurfaceKey(const Address &r,const int64_t rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalSocket(rol),reporterPhysicalAddress(ra),scope(s) {}
PhySurfaceKey() : reporter(), scope(InetAddress::IP_SCOPE_NONE)
{
}
PhySurfaceKey(const Address& r, const int64_t rol, const InetAddress& ra, InetAddress::IpScope s) : reporter(r), receivedOnLocalSocket(rol), reporterPhysicalAddress(ra), scope(s)
{
}
inline unsigned long hashCode() const { return ((unsigned long)reporter.toInt() + (unsigned long)scope); }
inline bool operator==(const PhySurfaceKey &k) const { return ((reporter == k.reporter)&&(receivedOnLocalSocket == k.receivedOnLocalSocket)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); }
inline unsigned long hashCode() const
{
return ((unsigned long)reporter.toInt() + (unsigned long)scope);
}
inline bool operator==(const PhySurfaceKey& k) const
{
return ((reporter == k.reporter) && (receivedOnLocalSocket == k.receivedOnLocalSocket) && (reporterPhysicalAddress == k.reporterPhysicalAddress) && (scope == k.scope));
}
};
struct PhySurfaceEntry
{
struct PhySurfaceEntry {
InetAddress mySurface;
uint64_t ts;
bool trusted;
PhySurfaceEntry() : mySurface(),ts(0),trusted(false) {}
PhySurfaceEntry(const InetAddress &a,const uint64_t t) : mySurface(a),ts(t),trusted(false) {}
PhySurfaceEntry() : mySurface(), ts(0), trusted(false)
{
}
PhySurfaceEntry(const InetAddress& a, const uint64_t t) : mySurface(a), ts(t), trusted(false)
{
}
};
const RuntimeEnvironment *RR;
const RuntimeEnvironment* RR;
Hashtable< PhySurfaceKey,PhySurfaceEntry > _phy;
Hashtable<PhySurfaceKey, PhySurfaceEntry> _phy;
Mutex _phy_m;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -14,8 +14,8 @@
#ifndef ZT_SHAREDPTR_HPP
#define ZT_SHAREDPTR_HPP
#include "Mutex.hpp"
#include "AtomicCounter.hpp"
#include "Mutex.hpp"
namespace ZeroTier {
@ -26,13 +26,18 @@ namespace ZeroTier {
* counted must list this as a 'friend' and must have a private instance of
* AtomicCounter called __refCount.
*/
template<typename T>
class SharedPtr
{
public:
SharedPtr() : _ptr((T *)0) {}
SharedPtr(T *obj) : _ptr(obj) { ++obj->__refCount; }
SharedPtr(const SharedPtr &sp) : _ptr(sp._getAndInc()) {}
template <typename T> class SharedPtr {
public:
SharedPtr() : _ptr((T*)0)
{
}
SharedPtr(T* obj) : _ptr(obj)
{
++obj->__refCount;
}
SharedPtr(const SharedPtr& sp) : _ptr(sp._getAndInc())
{
}
~SharedPtr()
{
@ -43,10 +48,10 @@ public:
}
}
inline SharedPtr &operator=(const SharedPtr &sp)
inline SharedPtr& operator=(const SharedPtr& sp)
{
if (_ptr != sp._ptr) {
T *p = sp._getAndInc();
T* p = sp._getAndInc();
if (_ptr) {
if (--_ptr->__refCount <= 0) {
delete _ptr;
@ -65,7 +70,7 @@ public:
*
* @param ptr Naked pointer to assign
*/
inline void set(T *ptr)
inline void set(T* ptr)
{
zero();
++ptr->__refCount;
@ -77,21 +82,33 @@ public:
*
* @param with Pointer to swap with
*/
inline void swap(SharedPtr &with)
inline void swap(SharedPtr& with)
{
T *tmp = _ptr;
T* tmp = _ptr;
_ptr = with._ptr;
with._ptr = tmp;
}
inline operator bool() const { return (_ptr != (T *)0); }
inline T &operator*() const { return *_ptr; }
inline T *operator->() const { return _ptr; }
inline operator bool() const
{
return (_ptr != (T*)0);
}
inline T& operator*() const
{
return *_ptr;
}
inline T* operator->() const
{
return _ptr;
}
/**
* @return Raw pointer to held object
*/
inline T *ptr() const { return _ptr; }
inline T* ptr() const
{
return _ptr;
}
/**
* Set this pointer to NULL
@ -102,7 +119,7 @@ public:
if (--_ptr->__refCount <= 0) {
delete _ptr;
}
_ptr = (T *)0;
_ptr = (T*)0;
}
}
@ -117,24 +134,42 @@ public:
return 0;
}
inline bool operator==(const SharedPtr &sp) const { return (_ptr == sp._ptr); }
inline bool operator!=(const SharedPtr &sp) const { return (_ptr != sp._ptr); }
inline bool operator>(const SharedPtr &sp) const { return (_ptr > sp._ptr); }
inline bool operator<(const SharedPtr &sp) const { return (_ptr < sp._ptr); }
inline bool operator>=(const SharedPtr &sp) const { return (_ptr >= sp._ptr); }
inline bool operator<=(const SharedPtr &sp) const { return (_ptr <= sp._ptr); }
inline bool operator==(const SharedPtr& sp) const
{
return (_ptr == sp._ptr);
}
inline bool operator!=(const SharedPtr& sp) const
{
return (_ptr != sp._ptr);
}
inline bool operator>(const SharedPtr& sp) const
{
return (_ptr > sp._ptr);
}
inline bool operator<(const SharedPtr& sp) const
{
return (_ptr < sp._ptr);
}
inline bool operator>=(const SharedPtr& sp) const
{
return (_ptr >= sp._ptr);
}
inline bool operator<=(const SharedPtr& sp) const
{
return (_ptr <= sp._ptr);
}
private:
inline T *_getAndInc() const
private:
inline T* _getAndInc() const
{
if (_ptr) {
++_ptr->__refCount;
}
return _ptr;
}
T *_ptr;
T* _ptr;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,32 +14,32 @@
#ifndef ZT_N_SWITCH_HPP
#define ZT_N_SWITCH_HPP
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "IncomingPacket.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include "Mutex.hpp"
#include "Network.hpp"
#include "Packet.hpp"
#include "SharedPtr.hpp"
#include "Topology.hpp"
#include "Utils.hpp"
#include <list>
#include <map>
#include <set>
#include <vector>
#include <list>
#include "Constants.hpp"
#include "Mutex.hpp"
#include "MAC.hpp"
#include "Packet.hpp"
#include "Utils.hpp"
#include "InetAddress.hpp"
#include "Topology.hpp"
#include "Network.hpp"
#include "SharedPtr.hpp"
#include "IncomingPacket.hpp"
#include "Hashtable.hpp"
/* 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_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_AARP 0x80f3
#define ZT_ETHERTYPE_IPX_A 0x8137
#define ZT_ETHERTYPE_IPX_B 0x8138
#define ZT_ETHERTYPE_IPV6 0x86dd
#define ZT_ETHERTYPE_IPV6 0x86dd
namespace ZeroTier {
@ -54,20 +54,19 @@ class Peer;
* 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
{
class Switch {
struct ManagedQueue;
struct TXQueueEntry;
friend class SharedPtr<Peer>;
typedef struct {
TXQueueEntry *p;
TXQueueEntry* p;
bool ok_to_drop;
} dqr;
public:
Switch(const RuntimeEnvironment *renv);
public:
Switch(const RuntimeEnvironment* renv);
/**
* Called when a packet is received from the real network
@ -78,7 +77,7 @@ public:
* @param data Packet data
* @param len Packet length
*/
void onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len);
void onRemotePacket(void* tPtr, const int64_t localSocket, const InetAddress& fromAddr, const void* data, unsigned int len);
/**
* Returns whether our bonding or balancing policy is aware of flows.
@ -97,7 +96,7 @@ public:
* @param data Ethernet payload
* @param len Frame length
*/
void onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
void onLocalEthernet(void* tPtr, const SharedPtr<Network>& network, const MAC& from, const MAC& to, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len);
/**
* Determines the next drop schedule for packets in the TX queue
@ -114,7 +113,7 @@ public:
* @param q The TX queue that is being dequeued from
* @param now Current time
*/
dqr dodequeue(ManagedQueue *q, uint64_t now);
dqr dodequeue(ManagedQueue* q, uint64_t now);
/**
* Presents a packet to the AQM scheduler.
@ -125,14 +124,14 @@ public:
* @param encrypt Encrypt packet payload? (always true except for HELLO)
* @param qosBucket Which bucket the rule-system determined this packet should fall into
*/
void aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &packet,bool encrypt,int qosBucket,int32_t flowId = ZT_QOS_NO_FLOW);
void aqm_enqueue(void* tPtr, const SharedPtr<Network>& network, Packet& packet, bool encrypt, int qosBucket, int32_t flowId = ZT_QOS_NO_FLOW);
/**
* Performs a single AQM cycle and dequeues and transmits all eligible packets on all networks
*
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/
void aqm_dequeue(void *tPtr);
void aqm_dequeue(void* tPtr);
/**
* Calls the dequeue mechanism and adjust queue state variables
@ -141,7 +140,7 @@ public:
* @param isNew Whether or not this queue is in the NEW list
* @param now Current time
*/
Switch::TXQueueEntry * CoDelDequeue(ManagedQueue *q, bool isNew, uint64_t now);
Switch::TXQueueEntry* CoDelDequeue(ManagedQueue* q, bool isNew, uint64_t now);
/**
* Removes QoS Queues and flow state variables for a specific network. These queues are created
@ -171,7 +170,7 @@ public:
* @param packet Packet to send (buffer may be modified)
* @param encrypt Encrypt packet payload? (always true except for HELLO)
*/
void send(void *tPtr,Packet &packet,bool encrypt,int32_t flowId = ZT_QOS_NO_FLOW);
void send(void* tPtr, Packet& packet, bool encrypt, int32_t flowId = ZT_QOS_NO_FLOW);
/**
* Request WHOIS on a given address
@ -180,7 +179,7 @@ public:
* @param now Current time
* @param addr Address to look up
*/
void requestWhois(void *tPtr,const int64_t now,const Address &addr);
void requestWhois(void* tPtr, const int64_t now, const Address& addr);
/**
* Run any processes that are waiting for this peer's identity
@ -190,7 +189,7 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param peer New peer
*/
void doAnythingWaitingForPeer(void *tPtr,const SharedPtr<Peer> &peer);
void doAnythingWaitingForPeer(void* tPtr, const SharedPtr<Peer>& peer);
/**
* Perform retries and other periodic timer tasks
@ -202,33 +201,34 @@ public:
* @param now Current time
* @return Number of milliseconds until doTimerTasks() should be run again
*/
unsigned long doTimerTasks(void *tPtr,int64_t now);
unsigned long doTimerTasks(void* tPtr, int64_t now);
private:
bool _shouldUnite(const int64_t now,const Address &source,const Address &destination);
bool _trySend(void *tPtr,Packet &packet,bool encrypt,int32_t flowId = ZT_QOS_NO_FLOW); // packet is modified if return is true
void _sendViaSpecificPath(void *tPtr,SharedPtr<Peer> peer,SharedPtr<Path> viaPath,uint16_t userSpecifiedMtu, int64_t now,Packet &packet,bool encrypt,int32_t flowId);
void _recordOutgoingPacketMetrics(const Packet &p);
private:
bool _shouldUnite(const int64_t now, const Address& source, const Address& destination);
bool _trySend(void* tPtr, Packet& packet, bool encrypt, int32_t flowId = ZT_QOS_NO_FLOW); // packet is modified if return is true
void _sendViaSpecificPath(void* tPtr, SharedPtr<Peer> peer, SharedPtr<Path> viaPath, uint16_t userSpecifiedMtu, int64_t now, Packet& packet, bool encrypt, int32_t flowId);
void _recordOutgoingPacketMetrics(const Packet& p);
const RuntimeEnvironment *const RR;
const RuntimeEnvironment* const RR;
int64_t _lastBeaconResponse;
volatile int64_t _lastCheckedQueues;
// Time we last sent a WHOIS request for each address
Hashtable< Address,int64_t > _lastSentWhoisRequest;
Hashtable<Address, int64_t> _lastSentWhoisRequest;
Mutex _lastSentWhoisRequest_m;
// Packets waiting for WHOIS replies or other decode info or missing fragments
struct RXQueueEntry
{
RXQueueEntry() : timestamp(0) {}
volatile int64_t timestamp; // 0 if entry is not in use
struct RXQueueEntry {
RXQueueEntry() : timestamp(0)
{
}
volatile int64_t timestamp; // 0 if entry is not in use
volatile 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
volatile bool complete; // if true, packet is complete
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
volatile bool complete; // if true, packet is complete
volatile int32_t flowId;
Mutex lock;
};
@ -236,12 +236,12 @@ private:
AtomicCounter _rxQueuePtr;
// Returns matching or next available RX queue entry
inline RXQueueEntry *_findRXQueueEntry(uint64_t packetId)
inline RXQueueEntry* _findRXQueueEntry(uint64_t packetId)
{
const unsigned int current = static_cast<unsigned int>(_rxQueuePtr.load());
for(unsigned int k=1;k<=ZT_RX_QUEUE_SIZE;++k) {
RXQueueEntry *rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]);
if ((rq->packetId == packetId)&&(rq->timestamp)) {
for (unsigned int k = 1; k <= ZT_RX_QUEUE_SIZE; ++k) {
RXQueueEntry* rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]);
if ((rq->packetId == packetId) && (rq->timestamp)) {
return rq;
}
}
@ -250,62 +250,64 @@ private:
}
// Returns current entry in rx queue ring buffer and increments ring pointer
inline RXQueueEntry *_nextRXQueueEntry()
inline RXQueueEntry* _nextRXQueueEntry()
{
return &(_rxQueue[static_cast<unsigned int>((++_rxQueuePtr) - 1) % ZT_RX_QUEUE_SIZE]);
}
// ZeroTier-layer TX queue entry
struct TXQueueEntry
{
TXQueueEntry() {}
TXQueueEntry(Address d,uint64_t ct,const Packet &p,bool enc,int32_t fid) :
dest(d),
creationTime(ct),
packet(p),
encrypt(enc),
flowId(fid) {}
struct TXQueueEntry {
TXQueueEntry()
{
}
TXQueueEntry(Address d, uint64_t ct, const Packet& p, bool enc, int32_t fid) : dest(d), creationTime(ct), packet(p), encrypt(enc), flowId(fid)
{
}
Address dest;
uint64_t creationTime;
Packet packet; // unencrypted/unMAC'd packet -- this is done at send time
Packet packet; // unencrypted/unMAC'd packet -- this is done at send time
bool encrypt;
int32_t flowId;
};
std::list< TXQueueEntry > _txQueue;
std::list<TXQueueEntry> _txQueue;
Mutex _txQueue_m;
Mutex _aqm_m;
// Tracks sending of VERB_RENDEZVOUS to relaying peers
struct _LastUniteKey
{
_LastUniteKey() : x(0),y(0) {}
_LastUniteKey(const Address &a1,const Address &a2)
struct _LastUniteKey {
_LastUniteKey() : x(0), y(0)
{
}
_LastUniteKey(const Address& a1, const Address& a2)
{
if (a1 > a2) {
x = a2.toInt();
y = a1.toInt();
} else {
}
else {
x = a1.toInt();
y = a2.toInt();
}
}
inline unsigned long hashCode() const { return ((unsigned long)x ^ (unsigned long)y); }
inline bool operator==(const _LastUniteKey &k) const { return ((x == k.x)&&(y == k.y)); }
uint64_t x,y;
inline unsigned long hashCode() const
{
return ((unsigned long)x ^ (unsigned long)y);
}
inline bool operator==(const _LastUniteKey& k) const
{
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
Hashtable<_LastUniteKey, uint64_t> _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior
Mutex _lastUniteAttempt_m;
// Queue with additional flow state variables
struct ManagedQueue
{
ManagedQueue(int id) :
id(id),
byteCredit(ZT_AQM_QUANTUM),
byteLength(0),
dropping(false)
{}
struct ManagedQueue {
ManagedQueue(int id) : id(id), byteCredit(ZT_AQM_QUANTUM), byteLength(0), dropping(false)
{
}
int id;
int byteCredit;
int byteLength;
@ -314,19 +316,18 @@ private:
uint64_t drop_next;
bool dropping;
uint64_t drop_next_time;
std::list< TXQueueEntry *> q;
std::list<TXQueueEntry*> q;
};
// To implement fq_codel we need to maintain a queue of queues
struct NetworkQoSControlBlock
{
struct NetworkQoSControlBlock {
int _currEnqueuedPackets;
std::vector<ManagedQueue *> newQueues;
std::vector<ManagedQueue *> oldQueues;
std::vector<ManagedQueue *> inactiveQueues;
std::vector<ManagedQueue*> newQueues;
std::vector<ManagedQueue*> oldQueues;
std::vector<ManagedQueue*> inactiveQueues;
};
std::map<uint64_t,NetworkQoSControlBlock*> _netQueueControlBlock;
std::map<uint64_t, NetworkQoSControlBlock*> _netQueueControlBlock;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -12,32 +12,34 @@
/****/
#include "Tag.hpp"
#include "RuntimeEnvironment.hpp"
#include "Identity.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier {
int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const
int Tag::verify(const RuntimeEnvironment* RR, void* tPtr) const
{
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) {
if ((! _signedBy) || (_signedBy != Network::controllerFor(_networkId))) {
return -1;
}
const Identity id(RR->topology->getIdentity(tPtr,_signedBy));
if (!id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy);
const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (! id) {
RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1;
}
try {
Buffer<(sizeof(Tag) * 2)> tmp;
this->serialize(tmp,true);
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
} catch ( ... ) {
this->serialize(tmp, true);
return (id.verify(tmp.data(), tmp.size(), _signature) ? 0 : -1);
}
catch (...) {
return -1;
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,18 +14,18 @@
#ifndef ZT_TAG_HPP
#define ZT_TAG_HPP
#include "Address.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "Identity.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Constants.hpp"
#include "Credential.hpp"
#include "C25519.hpp"
#include "Address.hpp"
#include "Identity.hpp"
#include "Buffer.hpp"
namespace ZeroTier {
class RuntimeEnvironment;
@ -47,18 +47,16 @@ class RuntimeEnvironment;
* Unlike capabilities tags are signed only by the issuer and are never
* transferable.
*/
class Tag : public Credential
{
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; }
Tag() :
_id(0),
_value(0),
_networkId(0),
_ts(0)
class Tag : public Credential {
public:
static inline Credential::Type credentialType()
{
memset(_signature.data,0,sizeof(_signature.data));
return Credential::CREDENTIAL_TYPE_TAG;
}
Tag() : _id(0), _value(0), _networkId(0), _ts(0)
{
memset(_signature.data, 0, sizeof(_signature.data));
}
/**
@ -68,23 +66,35 @@ public:
* @param id Tag ID
* @param value Tag value
*/
Tag(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) :
_id(id),
_value(value),
_networkId(nwid),
_ts(ts),
_issuedTo(issuedTo),
_signedBy()
Tag(const uint64_t nwid, const int64_t ts, const Address& issuedTo, const uint32_t id, const uint32_t value) : _id(id), _value(value), _networkId(nwid), _ts(ts), _issuedTo(issuedTo), _signedBy()
{
memset(_signature.data,0,sizeof(_signature.data));
memset(_signature.data, 0, sizeof(_signature.data));
}
inline uint32_t id() const { return _id; }
inline const uint32_t &value() const { return _value; }
inline uint64_t networkId() const { return _networkId; }
inline int64_t timestamp() const { return _ts; }
inline const Address &issuedTo() const { return _issuedTo; }
inline const Address &signedBy() const { return _signedBy; }
inline uint32_t id() const
{
return _id;
}
inline const uint32_t& value() const
{
return _value;
}
inline uint64_t networkId() const
{
return _networkId;
}
inline int64_t timestamp() const
{
return _ts;
}
inline const Address& issuedTo() const
{
return _issuedTo;
}
inline const Address& signedBy() const
{
return _signedBy;
}
/**
* Sign this tag
@ -92,13 +102,13 @@ public:
* @param signer Signing identity, must have private key
* @return True if signature was successful
*/
inline bool sign(const Identity &signer)
inline bool sign(const Identity& signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(Tag) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signature = signer.sign(tmp.data(),tmp.size());
this->serialize(tmp, true);
_signature = signer.sign(tmp.data(), tmp.size());
return true;
}
return false;
@ -111,10 +121,9 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag
*/
int verify(const RuntimeEnvironment *RR,void *tPtr) const;
int verify(const RuntimeEnvironment* RR, void* tPtr) const;
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
{
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -127,21 +136,20 @@ public:
_issuedTo.appendTo(b);
_signedBy.appendTo(b);
if (!forSign) {
b.append((uint8_t)1); // 1 == Ed25519
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
if (! forSign) {
b.append((uint8_t)1); // 1 == Ed25519
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_signature.data, ZT_C25519_SIGNATURE_LEN);
}
b.append((uint16_t)0); // length of additional fields, currently 0
b.append((uint16_t)0); // length of additional fields, currently 0
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
unsigned int p = startAt;
@ -157,18 +165,19 @@ public:
_value = b.template at<uint32_t>(p);
p += 4;
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
_issuedTo.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
_signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
}
p += 2;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
memcpy(_signature.data, b.field(p, ZT_C25519_SIGNATURE_LEN), ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else {
}
else {
p += 2 + b.template at<uint16_t>(p);
}
@ -181,26 +190,61 @@ public:
}
// Provides natural sort order by ID
inline bool operator<(const Tag &t) const { return (_id < t._id); }
inline bool operator<(const Tag& t) const
{
return (_id < t._id);
}
inline bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); }
inline bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); }
inline bool operator==(const Tag& t) const
{
return (memcmp(this, &t, sizeof(Tag)) == 0);
}
inline bool operator!=(const Tag& t) const
{
return (memcmp(this, &t, sizeof(Tag)) != 0);
}
// For searching sorted arrays or lists of Tags by ID
struct IdComparePredicate
{
inline bool operator()(const Tag &a,const Tag &b) const { return (a.id() < b.id()); }
inline bool operator()(const uint32_t a,const Tag &b) const { return (a < b.id()); }
inline bool operator()(const Tag &a,const uint32_t b) const { return (a.id() < b); }
inline bool operator()(const Tag *a,const Tag *b) const { return (a->id() < b->id()); }
inline bool operator()(const Tag *a,const Tag &b) const { return (a->id() < b.id()); }
inline bool operator()(const Tag &a,const Tag *b) const { return (a.id() < b->id()); }
inline bool operator()(const uint32_t a,const Tag *b) const { return (a < b->id()); }
inline bool operator()(const Tag *a,const uint32_t b) const { return (a->id() < b); }
inline bool operator()(const uint32_t a,const uint32_t b) const { return (a < b); }
struct IdComparePredicate {
inline bool operator()(const Tag& a, const Tag& b) const
{
return (a.id() < b.id());
}
inline bool operator()(const uint32_t a, const Tag& b) const
{
return (a < b.id());
}
inline bool operator()(const Tag& a, const uint32_t b) const
{
return (a.id() < b);
}
inline bool operator()(const Tag* a, const Tag* b) const
{
return (a->id() < b->id());
}
inline bool operator()(const Tag* a, const Tag& b) const
{
return (a->id() < b.id());
}
inline bool operator()(const Tag& a, const Tag* b) const
{
return (a.id() < b->id());
}
inline bool operator()(const uint32_t a, const Tag* b) const
{
return (a < b->id());
}
inline bool operator()(const Tag* a, const uint32_t b) const
{
return (a->id() < b);
}
inline bool operator()(const uint32_t a, const uint32_t b) const
{
return (a < b);
}
};
private:
private:
uint32_t _id;
uint32_t _value;
uint64_t _networkId;
@ -210,6 +254,6 @@ private:
C25519::Signature _signature;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,63 +11,79 @@
*/
/****/
#include "Constants.hpp"
#include "Topology.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Network.hpp"
#include "NetworkConfig.hpp"
#include "Buffer.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
namespace ZeroTier {
#define ZT_DEFAULT_WORLD_LENGTH 570
static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x7e,0xe9,0x57,0x60,0xcd,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,0x36,0x00,0x92,0x76,0x37,0xef,0x4d,0x14,0x04,0xa4,0x4d,0x54,0x46,0x84,0x85,0x13,0x79,0x75,0x1f,0xaa,0x79,0xb4,0xc4,0xea,0x85,0x04,0x01,0x75,0xea,0x06,0x58,0x60,0x48,0x24,0x02,0xe1,0xeb,0x34,0x20,0x52,0x00,0x0e,0x62,0x90,0x06,0x1a,0x9b,0xe0,0xcd,0x29,0x3c,0x8b,0x55,0xf1,0xc3,0xd2,0x52,0x48,0x08,0xaf,0xc5,0x49,0x22,0x08,0x0e,0x35,0x39,0xa7,0x5a,0xdd,0xc3,0xce,0xf0,0xf6,0xad,0x26,0x0d,0x58,0x82,0x93,0xbb,0x77,0x86,0xe7,0x1e,0xfa,0x4b,0x90,0x57,0xda,0xd9,0x86,0x7a,0xfe,0x12,0xdd,0x04,0xca,0xfe,0x9e,0xfe,0xb9,0x00,0xcc,0xde,0xf7,0x6b,0xc7,0xb9,0x7d,0xed,0x90,0x4e,0xab,0xc5,0xdf,0x09,0x88,0x6d,0x9c,0x15,0x14,0xa6,0x10,0x03,0x6c,0xb9,0x13,0x9c,0xc2,0x14,0x00,0x1a,0x29,0x58,0x97,0x8e,0xfc,0xec,0x15,0x71,0x2d,0xd3,0x94,0x8c,0x6e,0x6b,0x3a,0x8e,0x89,0x3d,0xf0,0x1f,0xf4,0x93,0xd1,0xf8,0xd9,0x80,0x6a,0x86,0x0c,0x54,0x20,0x57,0x1b,0xf0,0x00,0x02,0x04,0x68,0xc2,0x08,0x86,0x27,0x09,0x06,0x26,0x05,0x98,0x80,0x02,0x00,0x12,0x00,0x00,0x30,0x05,0x71,0x0e,0x34,0x00,0x51,0x27,0x09,0x77,0x8c,0xde,0x71,0x90,0x00,0x3f,0x66,0x81,0xa9,0x9e,0x5a,0xd1,0x89,0x5e,0x9f,0xba,0x33,0xe6,0x21,0x2d,0x44,0x54,0xe1,0x68,0xbc,0xec,0x71,0x12,0x10,0x1b,0xf0,0x00,0x95,0x6e,0xd8,0xe9,0x2e,0x42,0x89,0x2c,0xb6,0xf2,0xec,0x41,0x08,0x81,0xa8,0x4a,0xb1,0x9d,0xa5,0x0e,0x12,0x87,0xba,0x3d,0x92,0x6c,0x3a,0x1f,0x75,0x5c,0xcc,0xf2,0x99,0xa1,0x20,0x70,0x55,0x00,0x02,0x04,0x67,0xc3,0x67,0x42,0x27,0x09,0x06,0x26,0x05,0x98,0x80,0x04,0x00,0x00,0xc3,0x02,0x54,0xf2,0xbc,0xa1,0xf7,0x00,0x19,0x27,0x09,0x62,0xf8,0x65,0xae,0x71,0x00,0xe2,0x07,0x6c,0x57,0xde,0x87,0x0e,0x62,0x88,0xd7,0xd5,0xe7,0x40,0x44,0x08,0xb1,0x54,0x5e,0xfc,0xa3,0x7d,0x67,0xf7,0x7b,0x87,0xe9,0xe5,0x41,0x68,0xc2,0x5d,0x3e,0xf1,0xa9,0xab,0xf2,0x90,0x5e,0xa5,0xe7,0x85,0xc0,0x1d,0xff,0x23,0x88,0x7a,0xd4,0x23,0x2d,0x95,0xc7,0xa8,0xfd,0x2c,0x27,0x11,0x1a,0x72,0xbd,0x15,0x93,0x22,0xdc,0x00,0x02,0x04,0x32,0x07,0xfc,0x8a,0x27,0x09,0x06,0x20,0x01,0x49,0xf0,0xd0,0xdb,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0xca,0xfe,0x04,0xeb,0xa9,0x00,0x6c,0x6a,0x9d,0x1d,0xea,0x55,0xc1,0x61,0x6b,0xfe,0x2a,0x2b,0x8f,0x0f,0xf9,0xa8,0xca,0xca,0xf7,0x03,0x74,0xfb,0x1f,0x39,0xe3,0xbe,0xf8,0x1c,0xbf,0xeb,0xef,0x17,0xb7,0x22,0x82,0x68,0xa0,0xa2,0xa2,0x9d,0x34,0x88,0xc7,0x52,0x56,0x5c,0x6c,0x96,0x5c,0xbd,0x65,0x06,0xec,0x24,0x39,0x7c,0xc8,0xa5,0xd9,0xd1,0x52,0x85,0xa8,0x7f,0x00,0x02,0x04,0x54,0x11,0x35,0x9b,0x27,0x09,0x06,0x2a,0x02,0x6e,0xa0,0xd4,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x99,0x93,0x27,0x09};
static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xea, 0xc9, 0x0a, 0x00, 0x00, 0x01, 0x7e, 0xe9, 0x57, 0x60, 0xcd, 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, 0x36, 0x00, 0x92, 0x76, 0x37, 0xef, 0x4d, 0x14, 0x04, 0xa4, 0x4d, 0x54, 0x46, 0x84, 0x85, 0x13, 0x79, 0x75, 0x1f, 0xaa, 0x79, 0xb4, 0xc4, 0xea, 0x85, 0x04, 0x01, 0x75, 0xea, 0x06, 0x58, 0x60, 0x48,
0x24, 0x02, 0xe1, 0xeb, 0x34, 0x20, 0x52, 0x00, 0x0e, 0x62, 0x90, 0x06, 0x1a, 0x9b, 0xe0, 0xcd, 0x29, 0x3c, 0x8b, 0x55, 0xf1, 0xc3, 0xd2, 0x52, 0x48, 0x08, 0xaf, 0xc5, 0x49, 0x22, 0x08, 0x0e, 0x35, 0x39, 0xa7, 0x5a, 0xdd, 0xc3,
0xce, 0xf0, 0xf6, 0xad, 0x26, 0x0d, 0x58, 0x82, 0x93, 0xbb, 0x77, 0x86, 0xe7, 0x1e, 0xfa, 0x4b, 0x90, 0x57, 0xda, 0xd9, 0x86, 0x7a, 0xfe, 0x12, 0xdd, 0x04, 0xca, 0xfe, 0x9e, 0xfe, 0xb9, 0x00, 0xcc, 0xde, 0xf7, 0x6b, 0xc7, 0xb9,
0x7d, 0xed, 0x90, 0x4e, 0xab, 0xc5, 0xdf, 0x09, 0x88, 0x6d, 0x9c, 0x15, 0x14, 0xa6, 0x10, 0x03, 0x6c, 0xb9, 0x13, 0x9c, 0xc2, 0x14, 0x00, 0x1a, 0x29, 0x58, 0x97, 0x8e, 0xfc, 0xec, 0x15, 0x71, 0x2d, 0xd3, 0x94, 0x8c, 0x6e, 0x6b,
0x3a, 0x8e, 0x89, 0x3d, 0xf0, 0x1f, 0xf4, 0x93, 0xd1, 0xf8, 0xd9, 0x80, 0x6a, 0x86, 0x0c, 0x54, 0x20, 0x57, 0x1b, 0xf0, 0x00, 0x02, 0x04, 0x68, 0xc2, 0x08, 0x86, 0x27, 0x09, 0x06, 0x26, 0x05, 0x98, 0x80, 0x02, 0x00, 0x12, 0x00,
0x00, 0x30, 0x05, 0x71, 0x0e, 0x34, 0x00, 0x51, 0x27, 0x09, 0x77, 0x8c, 0xde, 0x71, 0x90, 0x00, 0x3f, 0x66, 0x81, 0xa9, 0x9e, 0x5a, 0xd1, 0x89, 0x5e, 0x9f, 0xba, 0x33, 0xe6, 0x21, 0x2d, 0x44, 0x54, 0xe1, 0x68, 0xbc, 0xec, 0x71,
0x12, 0x10, 0x1b, 0xf0, 0x00, 0x95, 0x6e, 0xd8, 0xe9, 0x2e, 0x42, 0x89, 0x2c, 0xb6, 0xf2, 0xec, 0x41, 0x08, 0x81, 0xa8, 0x4a, 0xb1, 0x9d, 0xa5, 0x0e, 0x12, 0x87, 0xba, 0x3d, 0x92, 0x6c, 0x3a, 0x1f, 0x75, 0x5c, 0xcc, 0xf2, 0x99,
0xa1, 0x20, 0x70, 0x55, 0x00, 0x02, 0x04, 0x67, 0xc3, 0x67, 0x42, 0x27, 0x09, 0x06, 0x26, 0x05, 0x98, 0x80, 0x04, 0x00, 0x00, 0xc3, 0x02, 0x54, 0xf2, 0xbc, 0xa1, 0xf7, 0x00, 0x19, 0x27, 0x09, 0x62, 0xf8, 0x65, 0xae, 0x71, 0x00,
0xe2, 0x07, 0x6c, 0x57, 0xde, 0x87, 0x0e, 0x62, 0x88, 0xd7, 0xd5, 0xe7, 0x40, 0x44, 0x08, 0xb1, 0x54, 0x5e, 0xfc, 0xa3, 0x7d, 0x67, 0xf7, 0x7b, 0x87, 0xe9, 0xe5, 0x41, 0x68, 0xc2, 0x5d, 0x3e, 0xf1, 0xa9, 0xab, 0xf2, 0x90, 0x5e,
0xa5, 0xe7, 0x85, 0xc0, 0x1d, 0xff, 0x23, 0x88, 0x7a, 0xd4, 0x23, 0x2d, 0x95, 0xc7, 0xa8, 0xfd, 0x2c, 0x27, 0x11, 0x1a, 0x72, 0xbd, 0x15, 0x93, 0x22, 0xdc, 0x00, 0x02, 0x04, 0x32, 0x07, 0xfc, 0x8a, 0x27, 0x09, 0x06, 0x20, 0x01,
0x49, 0xf0, 0xd0, 0xdb, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x27, 0x09, 0xca, 0xfe, 0x04, 0xeb, 0xa9, 0x00, 0x6c, 0x6a, 0x9d, 0x1d, 0xea, 0x55, 0xc1, 0x61, 0x6b, 0xfe, 0x2a, 0x2b, 0x8f, 0x0f, 0xf9, 0xa8,
0xca, 0xca, 0xf7, 0x03, 0x74, 0xfb, 0x1f, 0x39, 0xe3, 0xbe, 0xf8, 0x1c, 0xbf, 0xeb, 0xef, 0x17, 0xb7, 0x22, 0x82, 0x68, 0xa0, 0xa2, 0xa2, 0x9d, 0x34, 0x88, 0xc7, 0x52, 0x56, 0x5c, 0x6c, 0x96, 0x5c, 0xbd, 0x65, 0x06, 0xec, 0x24,
0x39, 0x7c, 0xc8, 0xa5, 0xd9, 0xd1, 0x52, 0x85, 0xa8, 0x7f, 0x00, 0x02, 0x04, 0x54, 0x11, 0x35, 0x9b, 0x27, 0x09, 0x06, 0x2a, 0x02, 0x6e, 0xa0, 0xd4, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x93, 0x27, 0x09
};
Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) :
RR(renv),
_numConfiguredPhysicalPaths(0),
_amUpstream(false)
Topology::Topology(const RuntimeEnvironment* renv, void* tPtr) : RR(renv), _numConfiguredPhysicalPaths(0), _amUpstream(false)
{
uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
uint64_t idtmp[2];
idtmp[0] = 0;
idtmp[1] = 0;
int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PLANET,idtmp,tmp,sizeof(tmp));
int n = RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_PLANET, idtmp, tmp, sizeof(tmp));
if (n > 0) {
try {
World cachedPlanet;
cachedPlanet.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp,(unsigned int)n),0);
addWorld(tPtr,cachedPlanet,false);
} catch ( ... ) {} // ignore invalid cached planets
cachedPlanet.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp, (unsigned int)n), 0);
addWorld(tPtr, cachedPlanet, false);
}
catch (...) {
} // ignore invalid cached planets
}
World defaultPlanet;
{
Buffer<ZT_DEFAULT_WORLD_LENGTH> wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH);
defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top
Buffer<ZT_DEFAULT_WORLD_LENGTH> wtmp(ZT_DEFAULT_WORLD, ZT_DEFAULT_WORLD_LENGTH);
defaultPlanet.deserialize(wtmp, 0); // throws on error, which would indicate a bad static variable up top
}
addWorld(tPtr,defaultPlanet,false);
addWorld(tPtr, defaultPlanet, false);
}
Topology::~Topology()
{
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
while (i.next(a,p)) {
_savePeer((void *)0,*p);
Hashtable<Address, SharedPtr<Peer> >::Iterator i(_peers);
Address* a = (Address*)0;
SharedPtr<Peer>* p = (SharedPtr<Peer>*)0;
while (i.next(a, p)) {
_savePeer((void*)0, *p);
}
}
SharedPtr<Peer> Topology::addPeer(void *tPtr,const SharedPtr<Peer> &peer)
SharedPtr<Peer> Topology::addPeer(void* tPtr, const SharedPtr<Peer>& peer)
{
SharedPtr<Peer> np;
{
Mutex::Lock _l(_peers_m);
SharedPtr<Peer> &hp = _peers[peer->address()];
if (!hp) {
SharedPtr<Peer>& hp = _peers[peer->address()];
if (! hp) {
hp = peer;
}
np = hp;
@ -75,7 +91,7 @@ SharedPtr<Peer> Topology::addPeer(void *tPtr,const SharedPtr<Peer> &peer)
return np;
}
SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
SharedPtr<Peer> Topology::getPeer(void* tPtr, const Address& zta)
{
if (zta == RR->identity.address()) {
return SharedPtr<Peer>();
@ -83,7 +99,7 @@ SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
{
Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta);
const SharedPtr<Peer>* const ap = _peers.get(zta);
if (ap) {
return *ap;
}
@ -94,32 +110,35 @@ SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
uint64_t idbuf[2];
idbuf[0] = zta.toInt();
idbuf[1] = 0;
int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf.unsafeData(),ZT_PEER_MAX_SERIALIZED_STATE_SIZE);
int len = RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_PEER, idbuf, buf.unsafeData(), ZT_PEER_MAX_SERIALIZED_STATE_SIZE);
if (len > 0) {
buf.setSize(len);
Mutex::Lock _l(_peers_m);
SharedPtr<Peer> &ap = _peers[zta];
SharedPtr<Peer>& ap = _peers[zta];
if (ap) {
return ap;
}
ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR);
if (!ap) {
ap = Peer::deserializeFromCache(RR->node->now(), tPtr, buf, RR);
if (! ap) {
_peers.erase(zta);
}
return SharedPtr<Peer>();
}
} catch ( ... ) {} // ignore invalid identities or other strange failures
}
catch (...) {
} // ignore invalid identities or other strange failures
return SharedPtr<Peer>();
}
Identity Topology::getIdentity(void *tPtr,const Address &zta)
Identity Topology::getIdentity(void* tPtr, const Address& zta)
{
if (zta == RR->identity.address()) {
return RR->identity;
} else {
}
else {
Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta);
const SharedPtr<Peer>* const ap = _peers.get(zta);
if (ap) {
return (*ap)->identity();
}
@ -131,13 +150,13 @@ SharedPtr<Peer> Topology::getUpstreamPeer()
{
const int64_t now = RR->node->now();
unsigned int bestq = ~((unsigned int)0);
const SharedPtr<Peer> *best = (const SharedPtr<Peer> *)0;
const SharedPtr<Peer>* best = (const SharedPtr<Peer>*)0;
Mutex::Lock _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m);
for(std::vector<Address>::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) {
const SharedPtr<Peer> *p = _peers.get(*a);
for (std::vector<Address>::const_iterator a(_upstreamAddresses.begin()); a != _upstreamAddresses.end(); ++a) {
const SharedPtr<Peer>* p = _peers.get(*a);
if (p) {
const unsigned int q = (*p)->relayQuality(now);
if (q <= bestq) {
@ -147,25 +166,25 @@ SharedPtr<Peer> Topology::getUpstreamPeer()
}
}
if (!best) {
if (! best) {
return SharedPtr<Peer>();
}
return *best;
}
bool Topology::isUpstream(const Identity &id) const
bool Topology::isUpstream(const Identity& id) const
{
Mutex::Lock _l(_upstreams_m);
return (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) != _upstreamAddresses.end());
return (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), id.address()) != _upstreamAddresses.end());
}
bool Topology::shouldAcceptWorldUpdateFrom(const Address &addr) const
bool Topology::shouldAcceptWorldUpdateFrom(const Address& addr) const
{
Mutex::Lock _l(_upstreams_m);
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),addr) != _upstreamAddresses.end()) {
if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), addr) != _upstreamAddresses.end()) {
return true;
}
for(std::vector< std::pair< uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) {
for (std::vector<std::pair<uint64_t, Address> >::const_iterator s(_moonSeeds.begin()); s != _moonSeeds.end(); ++s) {
if (s->second == addr) {
return true;
}
@ -173,11 +192,11 @@ bool Topology::shouldAcceptWorldUpdateFrom(const Address &addr) const
return false;
}
ZT_PeerRole Topology::role(const Address &ztaddr) const
ZT_PeerRole Topology::role(const Address& ztaddr) const
{
Mutex::Lock _l(_upstreams_m);
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) {
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), ztaddr) != _upstreamAddresses.end()) {
for (std::vector<World::Root>::const_iterator i(_planet.roots().begin()); i != _planet.roots().end(); ++i) {
if (i->identity.address() == ztaddr) {
return ZT_PEER_ROLE_PLANET;
}
@ -187,32 +206,32 @@ ZT_PeerRole Topology::role(const Address &ztaddr) const
return ZT_PEER_ROLE_LEAF;
}
bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const
bool Topology::isProhibitedEndpoint(const Address& ztaddr, const InetAddress& ipaddr) const
{
Mutex::Lock _l(_upstreams_m);
// For roots the only permitted addresses are those defined. This adds just a little
// bit of extra security against spoofing, replaying, etc.
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) {
for(std::vector<World::Root>::const_iterator r(_planet.roots().begin());r!=_planet.roots().end();++r) {
if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), ztaddr) != _upstreamAddresses.end()) {
for (std::vector<World::Root>::const_iterator r(_planet.roots().begin()); r != _planet.roots().end(); ++r) {
if (r->identity.address() == ztaddr) {
if (r->stableEndpoints.empty()) {
return false; // no stable endpoints specified, so allow dynamic paths
return false; // no stable endpoints specified, so allow dynamic paths
}
for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) {
for (std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin()); e != r->stableEndpoints.end(); ++e) {
if (ipaddr.ipsEqual(*e)) {
return false;
}
}
}
}
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
for(std::vector<World::Root>::const_iterator r(m->roots().begin());r!=m->roots().end();++r) {
for (std::vector<World>::const_iterator m(_moons.begin()); m != _moons.end(); ++m) {
for (std::vector<World::Root>::const_iterator r(m->roots().begin()); r != m->roots().end(); ++r) {
if (r->identity.address() == ztaddr) {
if (r->stableEndpoints.empty()) {
return false; // no stable endpoints specified, so allow dynamic paths
return false; // no stable endpoints specified, so allow dynamic paths
}
for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) {
for (std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin()); e != r->stableEndpoints.end(); ++e) {
if (ipaddr.ipsEqual(*e)) {
return false;
}
@ -226,22 +245,22 @@ bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipa
return false;
}
bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
bool Topology::addWorld(void* tPtr, const World& newWorld, bool alwaysAcceptNew)
{
if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON)) {
if ((newWorld.type() != World::TYPE_PLANET) && (newWorld.type() != World::TYPE_MOON)) {
return false;
}
Mutex::Lock _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m);
World *existing = (World *)0;
switch(newWorld.type()) {
World* existing = (World*)0;
switch (newWorld.type()) {
case World::TYPE_PLANET:
existing = &_planet;
break;
case World::TYPE_MOON:
for(std::vector< World >::iterator m(_moons.begin());m!=_moons.end();++m) {
for (std::vector<World>::iterator m(_moons.begin()); m != _moons.end(); ++m) {
if (m->id() == newWorld.id()) {
existing = &(*m);
break;
@ -255,17 +274,20 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
if (existing) {
if (existing->shouldBeReplacedBy(newWorld)) {
*existing = newWorld;
} else {
}
else {
return false;
}
} else if (newWorld.type() == World::TYPE_MOON) {
}
else if (newWorld.type() == World::TYPE_MOON) {
if (alwaysAcceptNew) {
_moons.push_back(newWorld);
existing = &(_moons.back());
} else {
for(std::vector< std::pair<uint64_t,Address> >::iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) {
}
else {
for (std::vector<std::pair<uint64_t, Address> >::iterator m(_moonSeeds.begin()); m != _moonSeeds.end(); ++m) {
if (m->first == newWorld.id()) {
for(std::vector<World::Root>::const_iterator r(newWorld.roots().begin());r!=newWorld.roots().end();++r) {
for (std::vector<World::Root>::const_iterator r(newWorld.roots().begin()); r != newWorld.roots().end(); ++r) {
if (r->identity.address() == m->second) {
_moonSeeds.erase(m);
_moons.push_back(newWorld);
@ -279,73 +301,79 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
}
}
}
if (!existing) {
if (! existing) {
return false;
}
} else {
}
else {
return false;
}
try {
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> sbuf;
existing->serialize(sbuf,false);
existing->serialize(sbuf, false);
uint64_t idtmp[2];
idtmp[0] = existing->id();
idtmp[1] = 0;
RR->node->stateObjectPut(tPtr,(existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON,idtmp,sbuf.data(),sbuf.size());
} catch ( ... ) {}
RR->node->stateObjectPut(tPtr, (existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON, idtmp, sbuf.data(), sbuf.size());
}
catch (...) {
}
_memoizeUpstreams(tPtr);
return true;
}
void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed)
void Topology::addMoon(void* tPtr, const uint64_t id, const Address& seed)
{
char tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
uint64_t idtmp[2];
idtmp[0] = id;
idtmp[1] = 0;
int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_MOON,idtmp,tmp,sizeof(tmp));
int n = RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_MOON, idtmp, tmp, sizeof(tmp));
if (n > 0) {
try {
World w;
w.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp,(unsigned int)n));
if ((w.type() == World::TYPE_MOON)&&(w.id() == id)) {
addWorld(tPtr,w,true);
w.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp, (unsigned int)n));
if ((w.type() == World::TYPE_MOON) && (w.id() == id)) {
addWorld(tPtr, w, true);
return;
}
} catch ( ... ) {}
}
catch (...) {
}
}
if (seed) {
Mutex::Lock _l(_upstreams_m);
if (std::find(_moonSeeds.begin(),_moonSeeds.end(),std::pair<uint64_t,Address>(id,seed)) == _moonSeeds.end()) {
_moonSeeds.push_back(std::pair<uint64_t,Address>(id,seed));
if (std::find(_moonSeeds.begin(), _moonSeeds.end(), std::pair<uint64_t, Address>(id, seed)) == _moonSeeds.end()) {
_moonSeeds.push_back(std::pair<uint64_t, Address>(id, seed));
}
}
}
void Topology::removeMoon(void *tPtr,const uint64_t id)
void Topology::removeMoon(void* tPtr, const uint64_t id)
{
Mutex::Lock _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m);
std::vector<World> nm;
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
for (std::vector<World>::const_iterator m(_moons.begin()); m != _moons.end(); ++m) {
if (m->id() != id) {
nm.push_back(*m);
} else {
}
else {
uint64_t idtmp[2];
idtmp[0] = id;
idtmp[1] = 0;
RR->node->stateObjectDelete(tPtr,ZT_STATE_OBJECT_MOON,idtmp);
RR->node->stateObjectDelete(tPtr, ZT_STATE_OBJECT_MOON, idtmp);
}
}
_moons.swap(nm);
std::vector< std::pair<uint64_t,Address> > cm;
for(std::vector< std::pair<uint64_t,Address> >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) {
std::vector<std::pair<uint64_t, Address> > cm;
for (std::vector<std::pair<uint64_t, Address> >::const_iterator m(_moonSeeds.begin()); m != _moonSeeds.end(); ++m) {
if (m->first != id) {
cm.push_back(*m);
}
@ -355,17 +383,17 @@ void Topology::removeMoon(void *tPtr,const uint64_t id)
_memoizeUpstreams(tPtr);
}
void Topology::doPeriodicTasks(void *tPtr,int64_t now)
void Topology::doPeriodicTasks(void* tPtr, int64_t now)
{
{
Mutex::Lock _l1(_peers_m);
Mutex::Lock _l2(_upstreams_m);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
while (i.next(a,p)) {
if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) {
_savePeer(tPtr,*p);
Hashtable<Address, SharedPtr<Peer> >::Iterator i(_peers);
Address* a = (Address*)0;
SharedPtr<Peer>* p = (SharedPtr<Peer>*)0;
while (i.next(a, p)) {
if ((! (*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), *a) == _upstreamAddresses.end())) {
_savePeer(tPtr, *p);
_peers.erase(*a);
}
}
@ -373,10 +401,10 @@ void Topology::doPeriodicTasks(void *tPtr,int64_t now)
{
Mutex::Lock _l(_paths_m);
Hashtable< Path::HashKey,SharedPtr<Path> >::Iterator i(_paths);
Path::HashKey *k = (Path::HashKey *)0;
SharedPtr<Path> *p = (SharedPtr<Path> *)0;
while (i.next(k,p)) {
Hashtable<Path::HashKey, SharedPtr<Path> >::Iterator i(_paths);
Path::HashKey* k = (Path::HashKey*)0;
SharedPtr<Path>* p = (SharedPtr<Path>*)0;
while (i.next(k, p)) {
if (p->references() <= 1) {
_paths.erase(*k);
}
@ -384,43 +412,45 @@ void Topology::doPeriodicTasks(void *tPtr,int64_t now)
}
}
void Topology::_memoizeUpstreams(void *tPtr)
void Topology::_memoizeUpstreams(void* tPtr)
{
// assumes _upstreams_m and _peers_m are locked
_upstreamAddresses.clear();
_amUpstream = false;
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
const Identity &id = i->identity;
for (std::vector<World::Root>::const_iterator i(_planet.roots().begin()); i != _planet.roots().end(); ++i) {
const Identity& id = i->identity;
if (id == RR->identity) {
_amUpstream = true;
} else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) == _upstreamAddresses.end()) {
}
else if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), id.address()) == _upstreamAddresses.end()) {
_upstreamAddresses.push_back(id.address());
SharedPtr<Peer> &hp = _peers[id.address()];
if (!hp) {
hp = new Peer(RR,RR->identity,id);
SharedPtr<Peer>& hp = _peers[id.address()];
if (! hp) {
hp = new Peer(RR, RR->identity, id);
}
}
}
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
for(std::vector<World::Root>::const_iterator i(m->roots().begin());i!=m->roots().end();++i) {
for (std::vector<World>::const_iterator m(_moons.begin()); m != _moons.end(); ++m) {
for (std::vector<World::Root>::const_iterator i(m->roots().begin()); i != m->roots().end(); ++i) {
if (i->identity == RR->identity) {
_amUpstream = true;
} else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) {
}
else if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), i->identity.address()) == _upstreamAddresses.end()) {
_upstreamAddresses.push_back(i->identity.address());
SharedPtr<Peer> &hp = _peers[i->identity.address()];
if (!hp) {
hp = new Peer(RR,RR->identity,i->identity);
SharedPtr<Peer>& hp = _peers[i->identity.address()];
if (! hp) {
hp = new Peer(RR, RR->identity, i->identity);
}
}
}
}
std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end());
std::sort(_upstreamAddresses.begin(), _upstreamAddresses.end());
}
void Topology::_savePeer(void *tPtr,const SharedPtr<Peer> &peer)
void Topology::_savePeer(void* tPtr, const SharedPtr<Peer>& peer)
{
try {
Buffer<ZT_PEER_MAX_SERIALIZED_STATE_SIZE> buf;
@ -428,8 +458,10 @@ void Topology::_savePeer(void *tPtr,const SharedPtr<Peer> &peer)
uint64_t tmpid[2];
tmpid[0] = peer->address().toInt();
tmpid[1] = 0;
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,tmpid,buf.data(),buf.size());
} catch ( ... ) {} // sanity check, discard invalid entries
RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_PEER, tmpid, buf.data(), buf.size());
}
catch (...) {
} // sanity check, discard invalid entries
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,25 +14,23 @@
#ifndef ZT_TOPOLOGY_HPP
#define ZT_TOPOLOGY_HPP
#include "../include/ZeroTierOne.h"
#include "Address.hpp"
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
#include "Mutex.hpp"
#include "Path.hpp"
#include "Peer.hpp"
#include "World.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <utility>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Address.hpp"
#include "Identity.hpp"
#include "Peer.hpp"
#include "Path.hpp"
#include "Mutex.hpp"
#include "InetAddress.hpp"
#include "Hashtable.hpp"
#include "World.hpp"
#include <vector>
namespace ZeroTier {
@ -41,10 +39,9 @@ class RuntimeEnvironment;
/**
* Database of network topology
*/
class Topology
{
public:
Topology(const RuntimeEnvironment *renv,void *tPtr);
class Topology {
public:
Topology(const RuntimeEnvironment* renv, void* tPtr);
~Topology();
/**
@ -57,7 +54,7 @@ public:
* @param peer Peer to add
* @return New or existing peer (should replace 'peer')
*/
SharedPtr<Peer> addPeer(void *tPtr,const SharedPtr<Peer> &peer);
SharedPtr<Peer> addPeer(void* tPtr, const SharedPtr<Peer>& peer);
/**
* Get a peer from its address
@ -66,14 +63,14 @@ public:
* @param zta ZeroTier address of peer
* @return Peer or NULL if not found
*/
SharedPtr<Peer> getPeer(void *tPtr,const Address &zta);
SharedPtr<Peer> getPeer(void* tPtr, const Address& zta);
/**
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param zta ZeroTier address of peer
* @return Identity or NULL identity if not found
*/
Identity getIdentity(void *tPtr,const Address &zta);
Identity getIdentity(void* tPtr, const Address& zta);
/**
* Get a peer only if it is presently in memory (no disk cache)
@ -85,10 +82,10 @@ public:
*
* @param zta ZeroTier address
*/
inline SharedPtr<Peer> getPeerNoCache(const Address &zta)
inline SharedPtr<Peer> getPeerNoCache(const Address& zta)
{
Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta);
const SharedPtr<Peer>* const ap = _peers.get(zta);
if (ap) {
return *ap;
}
@ -102,12 +99,12 @@ public:
* @param r Remote address
* @return Pointer to canonicalized Path object
*/
inline SharedPtr<Path> getPath(const int64_t l,const InetAddress &r)
inline SharedPtr<Path> getPath(const int64_t l, const InetAddress& r)
{
Mutex::Lock _l(_paths_m);
SharedPtr<Path> &p = _paths[Path::HashKey(l,r)];
if (!p) {
p.set(new Path(l,r));
SharedPtr<Path>& p = _paths[Path::HashKey(l, r)];
if (! p) {
p.set(new Path(l, r));
}
return p;
}
@ -123,19 +120,19 @@ public:
* @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;
bool isUpstream(const Identity& id) const;
/**
* @param addr Address to check
* @return True if we should accept a world update from this address
*/
bool shouldAcceptWorldUpdateFrom(const Address &addr) const;
bool shouldAcceptWorldUpdateFrom(const Address& addr) const;
/**
* @param ztaddr ZeroTier address
* @return Peer role for this device
*/
ZT_PeerRole role(const Address &ztaddr) const;
ZT_PeerRole role(const Address& ztaddr) const;
/**
* Check for prohibited endpoints
@ -151,39 +148,39 @@ public:
* @param ipaddr IP address
* @return True if this ZT/IP pair should not be allowed to be used
*/
bool isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const;
bool isProhibitedEndpoint(const Address& ztaddr, const InetAddress& ipaddr) const;
/**
* Gets upstreams to contact and their stable endpoints (if known)
*
* @param eps Hash table to fill with addresses and their stable endpoints
*/
inline void getUpstreamsToContact(Hashtable< Address,std::vector<InetAddress> > &eps) const
inline void getUpstreamsToContact(Hashtable<Address, std::vector<InetAddress> >& eps) const
{
Mutex::Lock _l(_upstreams_m);
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
for (std::vector<World::Root>::const_iterator i(_planet.roots().begin()); i != _planet.roots().end(); ++i) {
if (i->identity != RR->identity) {
std::vector<InetAddress> &ips = eps[i->identity.address()];
for(std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) {
if (std::find(ips.begin(),ips.end(),*j) == ips.end()) {
std::vector<InetAddress>& ips = eps[i->identity.address()];
for (std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin()); j != i->stableEndpoints.end(); ++j) {
if (std::find(ips.begin(), ips.end(), *j) == ips.end()) {
ips.push_back(*j);
}
}
}
}
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
for(std::vector<World::Root>::const_iterator i(m->roots().begin());i!=m->roots().end();++i) {
for (std::vector<World>::const_iterator m(_moons.begin()); m != _moons.end(); ++m) {
for (std::vector<World::Root>::const_iterator i(m->roots().begin()); i != m->roots().end(); ++i) {
if (i->identity != RR->identity) {
std::vector<InetAddress> &ips = eps[i->identity.address()];
for(std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) {
if (std::find(ips.begin(),ips.end(),*j) == ips.end()) {
std::vector<InetAddress>& ips = eps[i->identity.address()];
for (std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin()); j != i->stableEndpoints.end(); ++j) {
if (std::find(ips.begin(), ips.end(), *j) == ips.end()) {
ips.push_back(*j);
}
}
}
}
}
for(std::vector< std::pair<uint64_t,Address> >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) {
for (std::vector<std::pair<uint64_t, Address> >::const_iterator m(_moonSeeds.begin()); m != _moonSeeds.end(); ++m) {
eps[m->second];
}
}
@ -213,8 +210,8 @@ public:
{
Mutex::Lock _l(_upstreams_m);
std::vector<uint64_t> mw;
for(std::vector< std::pair<uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) {
if (std::find(mw.begin(),mw.end(),s->first) == mw.end()) {
for (std::vector<std::pair<uint64_t, Address> >::const_iterator s(_moonSeeds.begin()); s != _moonSeeds.end(); ++s) {
if (std::find(mw.begin(), mw.end(), s->first) == mw.end()) {
mw.push_back(s->first);
}
}
@ -235,7 +232,7 @@ public:
*/
inline uint64_t planetWorldId() const
{
return _planet.id(); // safe to read without lock, and used from within eachPeer() so don't lock
return _planet.id(); // safe to read without lock, and used from within eachPeer() so don't lock
}
/**
@ -243,7 +240,7 @@ public:
*/
inline uint64_t planetWorldTimestamp() const
{
return _planet.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock
return _planet.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock
}
/**
@ -254,7 +251,7 @@ public:
* @param alwaysAcceptNew If true, always accept new moons even if we're not waiting for one
* @return True if it was valid and newer than current (or totally new for moons)
*/
bool addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew);
bool addWorld(void* tPtr, const World& newWorld, bool alwaysAcceptNew);
/**
* Add a moon
@ -265,7 +262,7 @@ public:
* @param id Moon ID
* @param seed If non-NULL, an address of any member of the moon to contact
*/
void addMoon(void *tPtr,const uint64_t id,const Address &seed);
void addMoon(void* tPtr, const uint64_t id, const Address& seed);
/**
* Remove a moon
@ -273,12 +270,12 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param id Moon's world ID
*/
void removeMoon(void *tPtr,const uint64_t id);
void removeMoon(void* tPtr, const uint64_t id);
/**
* Clean and flush database
*/
void doPeriodicTasks(void *tPtr,int64_t now);
void doPeriodicTasks(void* tPtr, int64_t now);
/**
* @param now Current time
@ -288,11 +285,11 @@ public:
{
unsigned long cnt = 0;
Mutex::Lock _l(_peers_m);
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)) {
const SharedPtr<Path> pp((*p)->getAppropriatePath(now,false));
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)) {
const SharedPtr<Path> pp((*p)->getAppropriatePath(now, false));
if (pp) {
++cnt;
}
@ -306,22 +303,21 @@ public:
* @param f Function to apply
* @tparam F Function or function object type
*/
template<typename F>
inline void eachPeer(F f)
template <typename F> inline void eachPeer(F f)
{
Mutex::Lock _l(_peers_m);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
while (i.next(a,p)) {
f(*this,*((const SharedPtr<Peer> *)p));
Hashtable<Address, SharedPtr<Peer> >::Iterator i(_peers);
Address* a = (Address*)0;
SharedPtr<Peer>* p = (SharedPtr<Peer>*)0;
while (i.next(a, p)) {
f(*this, *((const SharedPtr<Peer>*)p));
}
}
/**
* @return All currently active peers by address (unsorted)
*/
inline std::vector< std::pair< Address,SharedPtr<Peer> > > allPeers() const
inline std::vector<std::pair<Address, SharedPtr<Peer> > > allPeers() const
{
Mutex::Lock _l(_peers_m);
return _peers.entries();
@ -330,7 +326,10 @@ public:
/**
* @return True if I am a root server in a planet or moon
*/
inline bool amUpstream() const { return _amUpstream; }
inline bool amUpstream() const
{
return _amUpstream;
}
/**
* Get info about a path
@ -341,9 +340,9 @@ public:
* @param mtu Variable set to MTU
* @param trustedPathId Variable set to trusted path ID
*/
inline void getOutboundPathInfo(const InetAddress &physicalAddress,unsigned int &mtu,uint64_t &trustedPathId)
inline void getOutboundPathInfo(const InetAddress& physicalAddress, unsigned int& mtu, uint64_t& trustedPathId)
{
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
for (unsigned int i = 0, j = _numConfiguredPhysicalPaths; i < j; ++i) {
if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
trustedPathId = _physicalPathConfig[i].second.trustedPathId;
mtu = _physicalPathConfig[i].second.mtu;
@ -358,9 +357,9 @@ public:
* @param physicalAddress Physical endpoint address
* @return MTU
*/
inline unsigned int getOutboundPathMtu(const InetAddress &physicalAddress)
inline unsigned int getOutboundPathMtu(const InetAddress& physicalAddress)
{
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
for (unsigned int i = 0, j = _numConfiguredPhysicalPaths; i < j; ++i) {
if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
return _physicalPathConfig[i].second.mtu;
}
@ -374,9 +373,9 @@ public:
* @param physicalAddress Physical address to which we are sending the packet
* @return Trusted path ID or 0 if none (0 is not a valid trusted path ID)
*/
inline uint64_t getOutboundPathTrust(const InetAddress &physicalAddress)
inline uint64_t getOutboundPathTrust(const InetAddress& physicalAddress)
{
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
for (unsigned int i = 0, j = _numConfiguredPhysicalPaths; i < j; ++i) {
if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
return _physicalPathConfig[i].second.trustedPathId;
}
@ -390,10 +389,10 @@ public:
* @param physicalAddress Originating physical address
* @param trustedPathId Trusted path ID from packet (from MAC field)
*/
inline bool shouldInboundPathBeTrusted(const InetAddress &physicalAddress,const uint64_t trustedPathId)
inline bool shouldInboundPathBeTrusted(const InetAddress& physicalAddress, const uint64_t trustedPathId)
{
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
if ((_physicalPathConfig[i].second.trustedPathId == trustedPathId)&&(_physicalPathConfig[i].first.containsAddress(physicalAddress))) {
for (unsigned int i = 0, j = _numConfiguredPhysicalPaths; i < j; ++i) {
if ((_physicalPathConfig[i].second.trustedPathId == trustedPathId) && (_physicalPathConfig[i].first.containsAddress(physicalAddress))) {
return true;
}
}
@ -403,13 +402,14 @@ public:
/**
* Set or clear physical path configuration (called via Node::setPhysicalPathConfiguration)
*/
inline void setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig)
inline void setPhysicalPathConfiguration(const struct sockaddr_storage* pathNetwork, const ZT_PhysicalPathConfiguration* pathConfig)
{
if (!pathNetwork) {
if (! pathNetwork) {
_numConfiguredPhysicalPaths = 0;
} else {
std::map<InetAddress,ZT_PhysicalPathConfiguration> cpaths;
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
}
else {
std::map<InetAddress, ZT_PhysicalPathConfiguration> cpaths;
for (unsigned int i = 0, j = _numConfiguredPhysicalPaths; i < j; ++i) {
cpaths[_physicalPathConfig[i].first] = _physicalPathConfig[i].second;
}
@ -418,19 +418,22 @@ public:
if (pc.mtu <= 0) {
pc.mtu = ZT_DEFAULT_PHYSMTU;
} else if (pc.mtu < ZT_MIN_PHYSMTU) {
}
else if (pc.mtu < ZT_MIN_PHYSMTU) {
pc.mtu = ZT_MIN_PHYSMTU;
} else if (pc.mtu > ZT_MAX_PHYSMTU) {
}
else if (pc.mtu > ZT_MAX_PHYSMTU) {
pc.mtu = ZT_MAX_PHYSMTU;
}
cpaths[*(reinterpret_cast<const InetAddress *>(pathNetwork))] = pc;
} else {
cpaths.erase(*(reinterpret_cast<const InetAddress *>(pathNetwork)));
cpaths[*(reinterpret_cast<const InetAddress*>(pathNetwork))] = pc;
}
else {
cpaths.erase(*(reinterpret_cast<const InetAddress*>(pathNetwork)));
}
unsigned int cnt = 0;
for(std::map<InetAddress,ZT_PhysicalPathConfiguration>::const_iterator i(cpaths.begin());((i!=cpaths.end())&&(cnt<ZT_MAX_CONFIGURABLE_PATHS));++i) {
for (std::map<InetAddress, ZT_PhysicalPathConfiguration>::const_iterator i(cpaths.begin()); ((i != cpaths.end()) && (cnt < ZT_MAX_CONFIGURABLE_PATHS)); ++i) {
_physicalPathConfig[cnt].first = i->first;
_physicalPathConfig[cnt].second = i->second;
++cnt;
@ -439,30 +442,30 @@ public:
}
}
private:
Identity _getIdentity(void *tPtr,const Address &zta);
void _memoizeUpstreams(void *tPtr);
void _savePeer(void *tPtr,const SharedPtr<Peer> &peer);
private:
Identity _getIdentity(void* tPtr, const Address& zta);
void _memoizeUpstreams(void* tPtr);
void _savePeer(void* tPtr, const SharedPtr<Peer>& peer);
const RuntimeEnvironment *const RR;
const RuntimeEnvironment* const RR;
std::pair<InetAddress,ZT_PhysicalPathConfiguration> _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
std::pair<InetAddress, ZT_PhysicalPathConfiguration> _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
volatile unsigned int _numConfiguredPhysicalPaths;
Hashtable< Address,SharedPtr<Peer> > _peers;
Hashtable<Address, SharedPtr<Peer> > _peers;
Mutex _peers_m;
Hashtable< Path::HashKey,SharedPtr<Path> > _paths;
Hashtable<Path::HashKey, SharedPtr<Path> > _paths;
Mutex _paths_m;
World _planet;
std::vector<World> _moons;
std::vector< std::pair<uint64_t,Address> > _moonSeeds;
std::vector<std::pair<uint64_t, Address> > _moonSeeds;
std::vector<Address> _upstreamAddresses;
bool _amUpstream;
Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc.
Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc.
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,21 +14,20 @@
#ifndef ZT_TRACE_HPP
#define ZT_TRACE_HPP
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "../include/ZeroTierOne.h"
#include "Constants.hpp"
#include "SharedPtr.hpp"
#include "Packet.hpp"
#include "Credential.hpp"
#include "InetAddress.hpp"
#include "Dictionary.hpp"
#include "Mutex.hpp"
#include "Hashtable.hpp"
#include "InetAddress.hpp"
#include "Mutex.hpp"
#include "Packet.hpp"
#include "SharedPtr.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
namespace ZeroTier {
@ -49,20 +48,12 @@ class Capability;
/**
* Remote tracing and trace logging handler
*/
class Trace
{
public:
class Trace {
public:
/**
* Trace verbosity level
*/
enum Level
{
LEVEL_NORMAL = 0,
LEVEL_VERBOSE = 10,
LEVEL_RULES = 15,
LEVEL_DEBUG = 20,
LEVEL_INSANE = 30
};
enum Level { LEVEL_NORMAL = 0, LEVEL_VERBOSE = 10, LEVEL_RULES = 15, LEVEL_DEBUG = 20, LEVEL_INSANE = 30 };
/**
* Filter rule evaluation result log
@ -73,67 +64,90 @@ public:
* As with four-bit rules an 00 value here means this was not
* evaluated or was not relevant.
*/
class RuleResultLog
{
public:
RuleResultLog() {}
inline void log(const unsigned int rn,const uint8_t thisRuleMatches,const uint8_t thisSetMatches)
class RuleResultLog {
public:
RuleResultLog()
{
_l[rn >> 1] |= ( ((thisRuleMatches + 1) << 2) | (thisSetMatches + 1) ) << ((rn & 1) << 2);
}
inline void logSkipped(const unsigned int rn,const uint8_t thisSetMatches)
inline void log(const unsigned int rn, const uint8_t thisRuleMatches, const uint8_t thisSetMatches)
{
_l[rn >> 1] |= (((thisRuleMatches + 1) << 2) | (thisSetMatches + 1)) << ((rn & 1) << 2);
}
inline void logSkipped(const unsigned int rn, const uint8_t thisSetMatches)
{
_l[rn >> 1] |= (thisSetMatches + 1) << ((rn & 1) << 2);
}
inline void clear()
{
memset(_l,0,sizeof(_l));
memset(_l, 0, sizeof(_l));
}
inline const uint8_t *data() const { return _l; }
inline unsigned int sizeBytes() const { return (ZT_MAX_NETWORK_RULES / 2); }
inline const uint8_t* data() const
{
return _l;
}
inline unsigned int sizeBytes() const
{
return (ZT_MAX_NETWORK_RULES / 2);
}
private:
private:
uint8_t _l[ZT_MAX_NETWORK_RULES / 2];
};
Trace(const RuntimeEnvironment *renv) :
RR(renv),
_byNet(8)
Trace(const RuntimeEnvironment* renv) : RR(renv), _byNet(8)
{
}
void resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope);
void resettingPathsInScope(void* const tPtr, const Address& reporter, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, const InetAddress::IpScope scope);
void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &path,const uint64_t packetId,const Packet::Verb verb);
void peerConfirmingUnknownPath(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr<Path>& path, const uint64_t packetId, const Packet::Verb verb);
void bondStateMessage(void *const tPtr,char *msg);
void bondStateMessage(void* const tPtr, char* msg);
void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath,const uint64_t packetId);
void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath);
void peerLearnedNewPath(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr<Path>& newPath, const uint64_t packetId);
void peerRedirected(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr<Path>& newPath);
void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason);
void incomingPacketInvalid(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason);
void incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const char *reason);
void incomingPacketMessageAuthenticationFailure(void* const tPtr, const SharedPtr<Path>& path, const uint64_t packetId, const Address& source, const unsigned int hops, const char* reason);
void incomingPacketInvalid(void* const tPtr, const SharedPtr<Path>& path, const uint64_t packetId, const Address& source, const unsigned int hops, const Packet::Verb verb, const char* reason);
void incomingPacketDroppedHELLO(void* const tPtr, const SharedPtr<Path>& path, const uint64_t packetId, const Address& source, const char* reason);
void outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason);
void incomingNetworkAccessDenied(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested);
void incomingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason);
void outgoingNetworkFrameDropped(void* const tPtr, const SharedPtr<Network>& network, const MAC& sourceMac, const MAC& destMac, const unsigned int etherType, const unsigned int vlanId, const unsigned int frameLen, const char* reason);
void incomingNetworkAccessDenied(
void* const tPtr,
const SharedPtr<Network>& network,
const SharedPtr<Path>& path,
const uint64_t packetId,
const unsigned int packetLength,
const Address& source,
const Packet::Verb verb,
bool credentialsRequested);
void incomingNetworkFrameDropped(
void* const tPtr,
const SharedPtr<Network>& network,
const SharedPtr<Path>& path,
const uint64_t packetId,
const unsigned int packetLength,
const Address& source,
const Packet::Verb verb,
const MAC& sourceMac,
const MAC& destMac,
const char* reason);
void networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller);
void networkConfigRequestSent(void* const tPtr, const Network& network, const Address& controller);
void networkFilter(
void *const tPtr,
const Network &network,
const RuleResultLog &primaryRuleSetLog,
const RuleResultLog *const matchingCapabilityRuleSetLog,
const Capability *const matchingCapability,
const Address &ztSource,
const Address &ztDest,
const MAC &macSource,
const MAC &macDest,
const uint8_t *const frameData,
void* const tPtr,
const Network& network,
const RuleResultLog& primaryRuleSetLog,
const RuleResultLog* const matchingCapabilityRuleSetLog,
const Capability* const matchingCapability,
const Address& ztSource,
const Address& ztDest,
const MAC& macSource,
const MAC& macDest,
const uint8_t* const frameData,
const unsigned int frameLen,
const unsigned int etherType,
const unsigned int vlanId,
@ -141,26 +155,26 @@ public:
const bool inbound,
const int accept);
void credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason);
void credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason);
void credentialRejected(void *const tPtr,const Capability &c,const char *reason);
void credentialRejected(void *const tPtr,const Tag &c,const char *reason);
void credentialRejected(void *const tPtr,const Revocation &c,const char *reason);
void credentialRejected(void* const tPtr, const CertificateOfMembership& c, const char* reason);
void credentialRejected(void* const tPtr, const CertificateOfOwnership& c, const char* reason);
void credentialRejected(void* const tPtr, const Capability& c, const char* reason);
void credentialRejected(void* const tPtr, const Tag& c, const char* reason);
void credentialRejected(void* const tPtr, const Revocation& c, const char* reason);
void updateMemoizedSettings();
private:
const RuntimeEnvironment *const RR;
private:
const RuntimeEnvironment* const RR;
void _send(void *const tPtr,const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> &d,const Address &dest);
void _spamToAllNetworks(void *const tPtr,const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> &d,const Level level);
void _send(void* const tPtr, const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE>& d, const Address& dest);
void _spamToAllNetworks(void* const tPtr, const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE>& d, const Level level);
Address _globalTarget;
Trace::Level _globalLevel;
Hashtable< uint64_t,std::pair< Address,Trace::Level > > _byNet;
Hashtable<uint64_t, std::pair<Address, Trace::Level> > _byNet;
Mutex _byNet_m;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,23 +11,23 @@
*/
/****/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <sys/stat.h>
#include "Constants.hpp"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#ifdef __UNIX_LIKE__
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <dirent.h>
#include <unistd.h>
#ifdef ZT_ARCH_ARM_HAS_NEON
#ifdef __LINUX__
#include <sys/auxv.h>
@ -36,13 +36,13 @@
#endif
#ifdef __WINDOWS__
#include <wincrypt.h>
#include <intrin.h>
#include <wincrypt.h>
#endif
#include "Utils.hpp"
#include "Mutex.hpp"
#include "Salsa20.hpp"
#include "Utils.hpp"
#ifdef __APPLE__
#include <TargetConditionals.h>
@ -55,8 +55,8 @@
#ifdef ZT_ARCH_ARM_HAS_NEON
#ifdef __LINUX__
#include <sys/auxv.h>
#include <asm/hwcap.h>
#include <sys/auxv.h>
#endif
#if defined(__FreeBSD__)
@ -87,36 +87,37 @@ static inline long getauxval(int caps)
#define HWCAP_SHA2 0
#endif
#endif // ZT_ARCH_ARM_HAS_NEON
#endif // ZT_ARCH_ARM_HAS_NEON
namespace ZeroTier {
const uint64_t Utils::ZERO256[4] = {0ULL,0ULL,0ULL,0ULL};
const uint64_t Utils::ZERO256[4] = { 0ULL, 0ULL, 0ULL, 0ULL };
const char Utils::HEXCHARS[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
const char Utils::HEXCHARS[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
#ifdef ZT_ARCH_ARM_HAS_NEON
Utils::ARMCapabilities::ARMCapabilities() noexcept
{
#ifdef __APPLE__
this->aes = true;
this->crc32 = true;
this->pmull = true;
this->sha1 = true;
this->sha2 = true;
this->aes = true;
this->crc32 = true;
this->pmull = true;
this->sha1 = true;
this->sha2 = true;
#else
#ifdef HWCAP2_AES
if (sizeof(void *) == 4) {
if (sizeof(void*) == 4) {
const long hwcaps2 = getauxval(AT_HWCAP2);
this->aes = (hwcaps2 & HWCAP2_AES) != 0;
this->crc32 = (hwcaps2 & HWCAP2_CRC32) != 0;
this->pmull = (hwcaps2 & HWCAP2_PMULL) != 0;
this->sha1 = (hwcaps2 & HWCAP2_SHA1) != 0;
this->sha2 = (hwcaps2 & HWCAP2_SHA2) != 0;
} else {
}
else {
#endif
const long hwcaps = getauxval(AT_HWCAP);
this->aes = (hwcaps & HWCAP_AES) != 0;
@ -128,7 +129,7 @@ Utils::ARMCapabilities::ARMCapabilities() noexcept
}
#endif
#endif // __APPLE__
#endif // __APPLE__
}
const Utils::ARMCapabilities Utils::ARMCAP;
@ -142,17 +143,13 @@ Utils::CPUIDRegisters::CPUIDRegisters() noexcept
#ifdef __WINDOWS__
int regs[4];
__cpuid(regs,1);
__cpuid(regs, 1);
eax = (uint32_t)regs[0];
ebx = (uint32_t)regs[1];
ecx = (uint32_t)regs[2];
edx = (uint32_t)regs[3];
#else
__asm__ __volatile__ (
"cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(1), "c"(0)
);
__asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1), "c"(0));
#endif
rdrand = ((ecx & (1U << 30U)) != 0);
@ -160,17 +157,13 @@ Utils::CPUIDRegisters::CPUIDRegisters() noexcept
avx = ((ecx & (1U << 25U)) != 0);
#ifdef __WINDOWS__
__cpuid(regs,7);
__cpuid(regs, 7);
eax = (uint32_t)regs[0];
ebx = (uint32_t)regs[1];
ecx = (uint32_t)regs[2];
edx = (uint32_t)regs[3];
#else
__asm__ __volatile__ (
"cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(7), "c"(0)
);
__asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(7), "c"(0));
#endif
vaes = aes && avx && ((ecx & (1U << 9U)) != 0);
@ -185,40 +178,43 @@ const Utils::CPUIDRegisters Utils::CPUID;
#endif
// Crazy hack to force memory to be securely zeroed in spite of the best efforts of optimizing compilers.
static void _Utils_doBurn(volatile uint8_t *ptr,unsigned int len)
static void _Utils_doBurn(volatile uint8_t* ptr, unsigned int len)
{
volatile uint8_t *const end = ptr + len;
volatile uint8_t* const end = ptr + len;
while (ptr != end) {
*(ptr++) = (uint8_t)0;
}
}
static void (*volatile _Utils_doBurn_ptr)(volatile uint8_t *,unsigned int) = _Utils_doBurn;
void Utils::burn(void *ptr,unsigned int len) { (_Utils_doBurn_ptr)((volatile uint8_t *)ptr,len); }
static void (*volatile _Utils_doBurn_ptr)(volatile uint8_t*, unsigned int) = _Utils_doBurn;
void Utils::burn(void* ptr, unsigned int len)
{
(_Utils_doBurn_ptr)((volatile uint8_t*)ptr, len);
}
static unsigned long _Utils_itoa(unsigned long n,char *s)
static unsigned long _Utils_itoa(unsigned long n, char* s)
{
if (n == 0) {
return 0;
}
unsigned long pos = _Utils_itoa(n / 10,s);
if (pos >= 22) { // sanity check, should be impossible
unsigned long pos = _Utils_itoa(n / 10, s);
if (pos >= 22) { // sanity check, should be impossible
pos = 22;
}
s[pos] = '0' + (char)(n % 10);
return pos + 1;
}
char *Utils::decimal(unsigned long n,char s[24])
char* Utils::decimal(unsigned long n, char s[24])
{
if (n == 0) {
s[0] = '0';
s[1] = (char)0;
return s;
}
s[_Utils_itoa(n,s)] = (char)0;
s[_Utils_itoa(n, s)] = (char)0;
return s;
}
void Utils::getSecureRandom(void *buf,unsigned int bytes)
void Utils::getSecureRandom(void* buf, unsigned int bytes)
{
static Mutex globalLock;
static Salsa20 s20;
@ -235,75 +231,76 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
* 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) {
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,s20Key);
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, s20Key);
}
#ifdef __WINDOWS__
static HCRYPTPROV cryptProvider = NULL;
for(unsigned int i=0;i<bytes;++i) {
for (unsigned int i = 0; i < bytes; ++i) {
if (randomPtr >= sizeof(randomBuf)) {
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");
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);
}
}
if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomBuf),(BYTE *)randomBuf)) {
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
if (! CryptGenRandom(cryptProvider, (DWORD)sizeof(randomBuf), (BYTE*)randomBuf)) {
fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
exit(1);
}
randomPtr = 0;
s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf));
s20.init(randomBuf,randomBuf);
s20.crypt12(randomBuf, randomBuf, sizeof(randomBuf));
s20.init(randomBuf, randomBuf);
}
((uint8_t *)buf)[i] = randomBuf[randomPtr++];
((uint8_t*)buf)[i] = randomBuf[randomPtr++];
}
#else // not __WINDOWS__
#else // not __WINDOWS__
static int devURandomFd = -1;
if (devURandomFd < 0) {
devURandomFd = ::open("/dev/urandom",O_RDONLY);
devURandomFd = ::open("/dev/urandom", O_RDONLY);
if (devURandomFd < 0) {
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
exit(1);
return;
}
}
for(unsigned int i=0;i<bytes;++i) {
for (unsigned int i = 0; i < bytes; ++i) {
if (randomPtr >= sizeof(randomBuf)) {
for(;;) {
if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
for (;;) {
if ((int)::read(devURandomFd, randomBuf, sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
::close(devURandomFd);
devURandomFd = ::open("/dev/urandom",O_RDONLY);
devURandomFd = ::open("/dev/urandom", O_RDONLY);
if (devURandomFd < 0) {
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
exit(1);
return;
}
} else {
}
else {
break;
}
}
randomPtr = 0;
s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf));
s20.init(randomBuf,randomBuf);
s20.crypt12(randomBuf, randomBuf, sizeof(randomBuf));
s20.init(randomBuf, randomBuf);
}
((uint8_t *)buf)[i] = randomBuf[randomPtr++];
((uint8_t*)buf)[i] = randomBuf[randomPtr++];
}
#endif // __WINDOWS__ or not
#endif // __WINDOWS__ or not
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,17 +14,16 @@
#ifndef ZT_UTILS_HPP
#define ZT_UTILS_HPP
#include <algorithm>
#include <map>
#include <stdexcept>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <string>
#include <stdexcept>
#include <time.h>
#include <vector>
#include <map>
#include <algorithm>
#if defined(__FreeBSD__)
#include <sys/endian.h>
@ -34,15 +33,9 @@
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U)))
#define ZT_CONST_TO_BE_UINT64(x) ( \
(((uint64_t)(x) & 0x00000000000000ffULL) << 56U) | \
(((uint64_t)(x) & 0x000000000000ff00ULL) << 40U) | \
(((uint64_t)(x) & 0x0000000000ff0000ULL) << 24U) | \
(((uint64_t)(x) & 0x00000000ff000000ULL) << 8U) | \
(((uint64_t)(x) & 0x000000ff00000000ULL) >> 8U) | \
(((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24U) | \
(((uint64_t)(x) & 0x00ff000000000000ULL) >> 40U) | \
(((uint64_t)(x) & 0xff00000000000000ULL) >> 56U))
#define ZT_CONST_TO_BE_UINT64(x) \
((((uint64_t)(x) & 0x00000000000000ffULL) << 56U) | (((uint64_t)(x) & 0x000000000000ff00ULL) << 40U) | (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24U) | (((uint64_t)(x) & 0x00000000ff000000ULL) << 8U) \
| (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8U) | (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24U) | (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40U) | (((uint64_t)(x) & 0xff00000000000000ULL) >> 56U))
#else
#define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)(x))
#define ZT_CONST_TO_BE_UINT64(x) ((uint64_t)(x))
@ -58,14 +51,12 @@ namespace ZeroTier {
/**
* Miscellaneous utility functions and global constants
*/
class Utils
{
public:
class Utils {
public:
static const uint64_t ZERO256[4];
#ifdef ZT_ARCH_ARM_HAS_NEON
struct ARMCapabilities
{
struct ARMCapabilities {
ARMCapabilities() noexcept;
bool aes;
@ -78,15 +69,14 @@ public:
#endif
#ifdef ZT_ARCH_X64
struct CPUIDRegisters
{
struct CPUIDRegisters {
CPUIDRegisters() noexcept;
bool rdrand;
bool aes;
bool avx;
bool vaes; // implies AVX
bool vpclmulqdq; // implies AVX
bool vaes; // implies AVX
bool vpclmulqdq; // implies AVX
bool avx2;
bool avx512f;
bool sha;
@ -97,7 +87,7 @@ public:
/**
* Compute the log2 (most significant bit set) of a 32-bit integer
*
*
* @param v Integer to compute
* @return log2 or 0 if v is 0
*/
@ -126,11 +116,11 @@ public:
* @param len Length of strings
* @return True if strings are equal
*/
static inline bool secureEq(const void *a,const void *b,unsigned int len)
static inline bool secureEq(const void* a, const void* b, unsigned int len)
{
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] );
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);
}
@ -138,16 +128,16 @@ public:
/**
* Securely zero memory, avoiding compiler optimizations and such
*/
static void burn(void *ptr,unsigned int len);
static void burn(void* ptr, unsigned int len);
/**
* @param n Number to convert
* @param s Buffer, at least 24 bytes in size
* @return String containing 'n' in base 10 form
*/
static char *decimal(unsigned long n,char s[24]);
static char* decimal(unsigned long n, char s[24]);
static inline char *hex(uint64_t i,char s[17])
static inline char* hex(uint64_t i, char s[17])
{
s[0] = HEXCHARS[(i >> 60) & 0xf];
s[1] = HEXCHARS[(i >> 56) & 0xf];
@ -169,7 +159,7 @@ public:
return s;
}
static inline char *hex10(uint64_t i,char s[11])
static inline char* hex10(uint64_t i, char s[11])
{
s[0] = HEXCHARS[(i >> 36) & 0xf];
s[1] = HEXCHARS[(i >> 32) & 0xf];
@ -185,7 +175,7 @@ public:
return s;
}
static inline char *hex(uint32_t i,char s[9])
static inline char* hex(uint32_t i, char s[9])
{
s[0] = HEXCHARS[(i >> 28) & 0xf];
s[1] = HEXCHARS[(i >> 24) & 0xf];
@ -199,7 +189,7 @@ public:
return s;
}
static inline char *hex(uint16_t i,char s[5])
static inline char* hex(uint16_t i, char s[5])
{
s[0] = HEXCHARS[(i >> 12) & 0xf];
s[1] = HEXCHARS[(i >> 8) & 0xf];
@ -209,7 +199,7 @@ public:
return s;
}
static inline char *hex(uint8_t i,char s[3])
static inline char* hex(uint8_t i, char s[3])
{
s[0] = HEXCHARS[(i >> 4) & 0xf];
s[1] = HEXCHARS[i & 0xf];
@ -217,11 +207,11 @@ public:
return s;
}
static inline char *hex(const void *d,unsigned int l,char *s)
static inline char* hex(const void* d, unsigned int l, char* s)
{
char *const save = s;
for(unsigned int i=0;i<l;++i) {
const unsigned int b = reinterpret_cast<const uint8_t *>(d)[i];
char* const save = s;
for (unsigned int i = 0; i < l; ++i) {
const unsigned int b = reinterpret_cast<const uint8_t*>(d)[i];
*(s++) = HEXCHARS[b >> 4];
*(s++) = HEXCHARS[b & 0xf];
}
@ -229,83 +219,91 @@ public:
return save;
}
static inline unsigned int unhex(const char *h,void *buf,unsigned int buflen)
static inline unsigned int unhex(const char* h, void* buf, unsigned int buflen)
{
unsigned int l = 0;
while (l < buflen) {
uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++));
if (!hc) {
uint8_t hc = *(reinterpret_cast<const uint8_t*>(h++));
if (! hc) {
break;
}
uint8_t c = 0;
if ((hc >= 48)&&(hc <= 57)) { // 0..9
if ((hc >= 48) && (hc <= 57)) { // 0..9
c = hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) { // a..f
}
else if ((hc >= 97) && (hc <= 102)) { // a..f
c = hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) { // A..F
}
else if ((hc >= 65) && (hc <= 70)) { // A..F
c = hc - 55;
}
hc = *(reinterpret_cast<const uint8_t *>(h++));
if (!hc) {
hc = *(reinterpret_cast<const uint8_t*>(h++));
if (! hc) {
break;
}
c <<= 4;
if ((hc >= 48)&&(hc <= 57)) {
if ((hc >= 48) && (hc <= 57)) {
c |= hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) {
}
else if ((hc >= 97) && (hc <= 102)) {
c |= hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) {
}
else if ((hc >= 65) && (hc <= 70)) {
c |= hc - 55;
}
reinterpret_cast<uint8_t *>(buf)[l++] = c;
reinterpret_cast<uint8_t*>(buf)[l++] = c;
}
return l;
}
static inline unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen)
static inline unsigned int unhex(const char* h, unsigned int hlen, void* buf, unsigned int buflen)
{
unsigned int l = 0;
const char *hend = h + hlen;
const char* hend = h + hlen;
while (l < buflen) {
if (h == hend) {
break;
}
uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++));
if (!hc) {
uint8_t hc = *(reinterpret_cast<const uint8_t*>(h++));
if (! hc) {
break;
}
uint8_t c = 0;
if ((hc >= 48)&&(hc <= 57)) {
if ((hc >= 48) && (hc <= 57)) {
c = hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) {
}
else if ((hc >= 97) && (hc <= 102)) {
c = hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) {
}
else if ((hc >= 65) && (hc <= 70)) {
c = hc - 55;
}
if (h == hend) {
break;
}
hc = *(reinterpret_cast<const uint8_t *>(h++));
if (!hc) {
hc = *(reinterpret_cast<const uint8_t*>(h++));
if (! hc) {
break;
}
c <<= 4;
if ((hc >= 48)&&(hc <= 57)) {
if ((hc >= 48) && (hc <= 57)) {
c |= hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) {
}
else if ((hc >= 97) && (hc <= 102)) {
c |= hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) {
}
else if ((hc >= 65) && (hc <= 70)) {
c |= hc - 55;
}
reinterpret_cast<uint8_t *>(buf)[l++] = c;
reinterpret_cast<uint8_t*>(buf)[l++] = c;
}
return l;
}
@ -327,7 +325,7 @@ public:
* @param buf Buffer to fill
* @param bytes Number of random bytes to generate
*/
static void getSecureRandom(void *buf,unsigned int bytes);
static void getSecureRandom(void* buf, unsigned int bytes);
/**
* Tokenize a string (alias for strtok_r or strtok_s depending on platform)
@ -336,54 +334,81 @@ public:
* @param delim Delimiters
* @param saveptr Pointer to a char * for temporary reentrant storage
*/
static inline char *stok(char *str,const char *delim,char **saveptr)
static inline char* stok(char* str, const char* delim, char** saveptr)
{
#ifdef __WINDOWS__
return strtok_s(str,delim,saveptr);
return strtok_s(str, delim, saveptr);
#else
return strtok_r(str,delim,saveptr);
return strtok_r(str, delim, saveptr);
#endif
}
static inline unsigned int strToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,10); }
static inline int strToInt(const char *s) { return (int)strtol(s,(char **)0,10); }
static inline unsigned long strToULong(const char *s) { return strtoul(s,(char **)0,10); }
static inline long strToLong(const char *s) { return strtol(s,(char **)0,10); }
static inline double strToDouble(const char *s) { return strtod(s,NULL); }
static inline unsigned long long strToU64(const char *s)
static inline unsigned int strToUInt(const char* s)
{
return (unsigned int)strtoul(s, (char**)0, 10);
}
static inline int strToInt(const char* s)
{
return (int)strtol(s, (char**)0, 10);
}
static inline unsigned long strToULong(const char* s)
{
return strtoul(s, (char**)0, 10);
}
static inline long strToLong(const char* s)
{
return strtol(s, (char**)0, 10);
}
static inline double strToDouble(const char* s)
{
return strtod(s, NULL);
}
static inline unsigned long long strToU64(const char* s)
{
#ifdef __WINDOWS__
return (unsigned long long)_strtoui64(s,(char **)0,10);
return (unsigned long long)_strtoui64(s, (char**)0, 10);
#else
return strtoull(s,(char **)0,10);
return strtoull(s, (char**)0, 10);
#endif
}
static inline long long strTo64(const char *s)
static inline long long strTo64(const char* s)
{
#ifdef __WINDOWS__
return (long long)_strtoi64(s,(char **)0,10);
return (long long)_strtoi64(s, (char**)0, 10);
#else
return strtoll(s,(char **)0,10);
return strtoll(s, (char**)0, 10);
#endif
}
static inline unsigned int hexStrToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,16); }
static inline int hexStrToInt(const char *s) { return (int)strtol(s,(char **)0,16); }
static inline unsigned long hexStrToULong(const char *s) { return strtoul(s,(char **)0,16); }
static inline long hexStrToLong(const char *s) { return strtol(s,(char **)0,16); }
static inline unsigned long long hexStrToU64(const char *s)
static inline unsigned int hexStrToUInt(const char* s)
{
return (unsigned int)strtoul(s, (char**)0, 16);
}
static inline int hexStrToInt(const char* s)
{
return (int)strtol(s, (char**)0, 16);
}
static inline unsigned long hexStrToULong(const char* s)
{
return strtoul(s, (char**)0, 16);
}
static inline long hexStrToLong(const char* s)
{
return strtol(s, (char**)0, 16);
}
static inline unsigned long long hexStrToU64(const char* s)
{
#ifdef __WINDOWS__
return (unsigned long long)_strtoui64(s,(char **)0,16);
return (unsigned long long)_strtoui64(s, (char**)0, 16);
#else
return strtoull(s,(char **)0,16);
return strtoull(s, (char**)0, 16);
#endif
}
static inline long long hexStrTo64(const char *s)
static inline long long hexStrTo64(const char* s)
{
#ifdef __WINDOWS__
return (long long)_strtoi64(s,(char **)0,16);
return (long long)_strtoi64(s, (char**)0, 16);
#else
return strtoll(s,(char **)0,16);
return strtoll(s, (char**)0, 16);
#endif
}
@ -398,16 +423,16 @@ public:
* @param src Source string (if NULL, dest will receive a zero-length string and true is returned)
* @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)
static inline bool scopy(char* dest, unsigned int len, const char* src)
{
if (!len) {
return false; // sanity check
if (! len) {
return false; // sanity check
}
if (!src) {
if (! src) {
*dest = (char)0;
return true;
}
char *end = dest + len;
char* end = dest + len;
while ((*dest++ = *src++)) {
if (dest == end) {
*(--dest) = (char)0;
@ -438,10 +463,10 @@ public:
*/
static inline uint64_t countBits(uint64_t v)
{
v = v - ((v >> 1) & (uint64_t)~(uint64_t)0/3);
v = (v & (uint64_t)~(uint64_t)0/15*3) + ((v >> 2) & (uint64_t)~(uint64_t)0/15*3);
v = (v + (v >> 4)) & (uint64_t)~(uint64_t)0/255*15;
return (uint64_t)(v * ((uint64_t)~(uint64_t)0/255)) >> 56;
v = v - ((v >> 1) & (uint64_t)~(uint64_t)0 / 3);
v = (v & (uint64_t)~(uint64_t)0 / 15 * 3) + ((v >> 2) & (uint64_t)~(uint64_t)0 / 15 * 3);
v = (v + (v >> 4)) & (uint64_t)~(uint64_t)0 / 255 * 15;
return (uint64_t)(v * ((uint64_t)~(uint64_t)0 / 255)) >> 56;
}
/**
@ -451,10 +476,10 @@ public:
* @param len Length of memory
* @return True if memory is all zero
*/
static inline bool isZero(const void *p,unsigned int len)
static inline bool isZero(const void* p, unsigned int len)
{
for(unsigned int i=0;i<len;++i) {
if (((const unsigned char *)p)[i]) {
for (unsigned int i = 0; i < len; ++i) {
if (((const unsigned char*)p)[i]) {
return false;
}
}
@ -469,24 +494,17 @@ public:
*/
static ZT_INLINE uint64_t swapBytes(const uint64_t n) noexcept
{
#ifdef __GNUC__
#ifdef __GNUC__
return __builtin_bswap64(n);
#else
#ifdef _MSC_VER
#else
#ifdef _MSC_VER
return (uint64_t)_byteswap_uint64((unsigned __int64)n);
#else
#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
#endif
((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
#endif
}
/**
@ -497,15 +515,15 @@ public:
*/
static ZT_INLINE uint32_t swapBytes(const uint32_t n) noexcept
{
#if defined(__GNUC__)
#if defined(__GNUC__)
return __builtin_bswap32(n);
#else
#ifdef _MSC_VER
#else
#ifdef _MSC_VER
return (uint32_t)_byteswap_ulong((unsigned long)n);
#else
#else
return htonl(n);
#endif
#endif
#endif
#endif
}
/**
@ -516,122 +534,119 @@ public:
*/
static ZT_INLINE uint16_t swapBytes(const uint16_t n) noexcept
{
#if defined(__GNUC__)
#if defined(__GNUC__)
return __builtin_bswap16(n);
#else
#ifdef _MSC_VER
#else
#ifdef _MSC_VER
return (uint16_t)_byteswap_ushort((unsigned short)n);
#else
#else
return htons(n);
#endif
#endif
#endif
#endif
}
// These are helper adapters to load and swap integer types special cased by size
// to work with all typedef'd variants, signed/unsigned, etc.
template< typename I, unsigned int S >
class _swap_bytes_bysize;
template <typename I, unsigned int S> class _swap_bytes_bysize;
template< typename I >
class _swap_bytes_bysize< I, 1 >
{
public:
template <typename I> class _swap_bytes_bysize<I, 1> {
public:
static ZT_INLINE I s(const I n) noexcept
{ return n; }
{
return n;
}
};
template< typename I >
class _swap_bytes_bysize< I, 2 >
{
public:
template <typename I> class _swap_bytes_bysize<I, 2> {
public:
static ZT_INLINE I s(const I n) noexcept
{ return (I)swapBytes((uint16_t)n); }
{
return (I)swapBytes((uint16_t)n);
}
};
template< typename I >
class _swap_bytes_bysize< I, 4 >
{
public:
template <typename I> class _swap_bytes_bysize<I, 4> {
public:
static ZT_INLINE I s(const I n) noexcept
{ return (I)swapBytes((uint32_t)n); }
{
return (I)swapBytes((uint32_t)n);
}
};
template< typename I >
class _swap_bytes_bysize< I, 8 >
{
public:
template <typename I> class _swap_bytes_bysize<I, 8> {
public:
static ZT_INLINE I s(const I n) noexcept
{ return (I)swapBytes((uint64_t)n); }
{
return (I)swapBytes((uint64_t)n);
}
};
template< typename I, unsigned int S >
class _load_be_bysize;
template <typename I, unsigned int S> class _load_be_bysize;
template< typename I >
class _load_be_bysize< I, 1 >
{
public:
static ZT_INLINE I l(const uint8_t *const p) noexcept
{ return p[0]; }
template <typename I> class _load_be_bysize<I, 1> {
public:
static ZT_INLINE I l(const uint8_t* const p) noexcept
{
return p[0];
}
};
template< typename I >
class _load_be_bysize< I, 2 >
{
public:
static ZT_INLINE I l(const uint8_t *const p) noexcept
{ return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]); }
template <typename I> class _load_be_bysize<I, 2> {
public:
static ZT_INLINE I l(const uint8_t* const p) noexcept
{
return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]);
}
};
template< typename I >
class _load_be_bysize< I, 4 >
{
public:
static ZT_INLINE I l(const uint8_t *const p) noexcept
{ return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]); }
template <typename I> class _load_be_bysize<I, 4> {
public:
static ZT_INLINE I l(const uint8_t* const p) noexcept
{
return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]);
}
};
template< typename I >
class _load_be_bysize< I, 8 >
{
public:
static ZT_INLINE I l(const uint8_t *const p) noexcept
{ return (I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]); }
template <typename I> class _load_be_bysize<I, 8> {
public:
static ZT_INLINE I l(const uint8_t* const p) noexcept
{
return (I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]);
}
};
template< typename I, unsigned int S >
class _load_le_bysize;
template <typename I, unsigned int S> class _load_le_bysize;
template< typename I >
class _load_le_bysize< I, 1 >
{
public:
static ZT_INLINE I l(const uint8_t *const p) noexcept
{ return p[0]; }
template <typename I> class _load_le_bysize<I, 1> {
public:
static ZT_INLINE I l(const uint8_t* const p) noexcept
{
return p[0];
}
};
template< typename I >
class _load_le_bysize< I, 2 >
{
public:
static ZT_INLINE I l(const uint8_t *const p) noexcept
{ return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U)); }
template <typename I> class _load_le_bysize<I, 2> {
public:
static ZT_INLINE I l(const uint8_t* const p) noexcept
{
return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U));
}
};
template< typename I >
class _load_le_bysize< I, 4 >
{
public:
static ZT_INLINE I l(const uint8_t *const p) noexcept
{ return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U)); }
template <typename I> class _load_le_bysize<I, 4> {
public:
static ZT_INLINE I l(const uint8_t* const p) noexcept
{
return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U));
}
};
template< typename I >
class _load_le_bysize< I, 8 >
{
public:
static ZT_INLINE I l(const uint8_t *const p) noexcept
{ return (I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U); }
template <typename I> class _load_le_bysize<I, 8> {
public:
static ZT_INLINE I l(const uint8_t* const p) noexcept
{
return (I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U);
}
};
/**
@ -641,14 +656,13 @@ public:
* @param n Value to convert
* @return Value in big-endian order
*/
template< typename I >
static ZT_INLINE I hton(const I n) noexcept
template <typename I> static ZT_INLINE I hton(const I n) noexcept
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
return _swap_bytes_bysize< I, sizeof(I) >::s(n);
#else
#if __BYTE_ORDER == __LITTLE_ENDIAN
return _swap_bytes_bysize<I, sizeof(I)>::s(n);
#else
return n;
#endif
#endif
}
/**
@ -658,14 +672,13 @@ public:
* @param n Value to convert
* @return Value in host byte order
*/
template< typename I >
static ZT_INLINE I ntoh(const I n) noexcept
template <typename I> static ZT_INLINE I ntoh(const I n) noexcept
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
return _swap_bytes_bysize< I, sizeof(I) >::s(n);
#else
#if __BYTE_ORDER == __LITTLE_ENDIAN
return _swap_bytes_bysize<I, sizeof(I)>::s(n);
#else
return n;
#endif
#endif
}
/**
@ -675,18 +688,17 @@ public:
* @param p Byte stream, must be at least sizeof(I) in size
* @return Loaded raw integer
*/
template< typename I >
static ZT_INLINE I loadMachineEndian(const void *const p) noexcept
template <typename I> static ZT_INLINE I loadMachineEndian(const void* const p) noexcept
{
#ifdef ZT_NO_UNALIGNED_ACCESS
#ifdef ZT_NO_UNALIGNED_ACCESS
I tmp;
for(int i=0;i<(int)sizeof(I);++i) {
reinterpret_cast<uint8_t *>(&tmp)[i] = reinterpret_cast<const uint8_t *>(p)[i];
for (int i = 0; i < (int)sizeof(I); ++i) {
reinterpret_cast<uint8_t*>(&tmp)[i] = reinterpret_cast<const uint8_t*>(p)[i];
}
return tmp;
#else
return *reinterpret_cast<const I *>(p);
#endif
#else
return *reinterpret_cast<const I*>(p);
#endif
}
/**
@ -696,16 +708,15 @@ public:
* @param p Byte array (must be at least sizeof(I))
* @param i Integer to store
*/
template< typename I >
static ZT_INLINE void storeMachineEndian(void *const p, const I i) noexcept
template <typename I> static ZT_INLINE void storeMachineEndian(void* const p, const I i) noexcept
{
#ifdef ZT_NO_UNALIGNED_ACCESS
for(unsigned int k=0;k<sizeof(I);++k) {
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[k];
#ifdef ZT_NO_UNALIGNED_ACCESS
for (unsigned int k = 0; k < sizeof(I); ++k) {
reinterpret_cast<uint8_t*>(p)[k] = reinterpret_cast<const uint8_t*>(&i)[k];
}
#else
*reinterpret_cast<I *>(p) = i;
#endif
#else
*reinterpret_cast<I*>(p) = i;
#endif
}
/**
@ -715,14 +726,13 @@ public:
* @param p Byte stream, must be at least sizeof(I) in size
* @return Decoded integer
*/
template< typename I >
static ZT_INLINE I loadBigEndian(const void *const p) noexcept
template <typename I> static ZT_INLINE I loadBigEndian(const void* const p) noexcept
{
#ifdef ZT_NO_UNALIGNED_ACCESS
return _load_be_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p));
#else
return ntoh(*reinterpret_cast<const I *>(p));
#endif
#ifdef ZT_NO_UNALIGNED_ACCESS
return _load_be_bysize<I, sizeof(I)>::l(reinterpret_cast<const uint8_t*>(p));
#else
return ntoh(*reinterpret_cast<const I*>(p));
#endif
}
/**
@ -732,14 +742,13 @@ public:
* @param p Byte stream to write (must be at least sizeof(I))
* #param i Integer to write
*/
template< typename I >
static ZT_INLINE void storeBigEndian(void *const p, I i) noexcept
template <typename I> static ZT_INLINE void storeBigEndian(void* const p, I i) noexcept
{
#ifdef ZT_NO_UNALIGNED_ACCESS
storeMachineEndian(p,hton(i));
#else
*reinterpret_cast<I *>(p) = hton(i);
#endif
#ifdef ZT_NO_UNALIGNED_ACCESS
storeMachineEndian(p, hton(i));
#else
*reinterpret_cast<I*>(p) = hton(i);
#endif
}
/**
@ -749,14 +758,13 @@ public:
* @param p Byte stream, must be at least sizeof(I) in size
* @return Decoded integer
*/
template< typename I >
static ZT_INLINE I loadLittleEndian(const void *const p) noexcept
template <typename I> static ZT_INLINE I loadLittleEndian(const void* const p) noexcept
{
#if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
return _load_le_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p));
#else
return *reinterpret_cast<const I *>(p);
#endif
#if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
return _load_le_bysize<I, sizeof(I)>::l(reinterpret_cast<const uint8_t*>(p));
#else
return *reinterpret_cast<const I*>(p);
#endif
}
/**
@ -766,18 +774,17 @@ public:
* @param p Byte stream to write (must be at least sizeof(I))
* #param i Integer to write
*/
template< typename I >
static ZT_INLINE void storeLittleEndian(void *const p, const I i) noexcept
template <typename I> static ZT_INLINE void storeLittleEndian(void* const p, const I i) noexcept
{
#if __BYTE_ORDER == __BIG_ENDIAN
storeMachineEndian(p,_swap_bytes_bysize<I,sizeof(I)>::s(i));
#else
#ifdef ZT_NO_UNALIGNED_ACCESS
storeMachineEndian(p,i);
#else
*reinterpret_cast<I *>(p) = i;
#endif
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
storeMachineEndian(p, _swap_bytes_bysize<I, sizeof(I)>::s(i));
#else
#ifdef ZT_NO_UNALIGNED_ACCESS
storeMachineEndian(p, i);
#else
*reinterpret_cast<I*>(p) = i;
#endif
#endif
}
/**
@ -787,15 +794,14 @@ public:
* @param dest Destination memory
* @param src Source memory
*/
template< unsigned long L >
static ZT_INLINE void copy(void *dest, const void *src) noexcept
template <unsigned long L> static ZT_INLINE void copy(void* dest, const void* src) noexcept
{
#if defined(ZT_ARCH_X64) && defined(__GNUC__)
#if defined(ZT_ARCH_X64) && defined(__GNUC__)
uintptr_t l = L;
__asm__ __volatile__ ("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest) :: "memory");
#else
__asm__ __volatile__("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest)::"memory");
#else
memcpy(dest, src, L);
#endif
#endif
}
/**
@ -805,13 +811,13 @@ public:
* @param src Source memory
* @param len Bytes to copy
*/
static ZT_INLINE void copy(void *dest, const void *src, unsigned long len) noexcept
static ZT_INLINE void copy(void* dest, const void* src, unsigned long len) noexcept
{
#if defined(ZT_ARCH_X64) && defined(__GNUC__)
__asm__ __volatile__ ("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest) :: "memory");
#else
#if defined(ZT_ARCH_X64) && defined(__GNUC__)
__asm__ __volatile__("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest)::"memory");
#else
memcpy(dest, src, len);
#endif
#endif
}
/**
@ -820,15 +826,14 @@ public:
* @tparam L Size in bytes
* @param dest Memory to zero
*/
template< unsigned long L >
static ZT_INLINE void zero(void *dest) noexcept
template <unsigned long L> static ZT_INLINE void zero(void* dest) noexcept
{
#if defined(ZT_ARCH_X64) && defined(__GNUC__)
#if defined(ZT_ARCH_X64) && defined(__GNUC__)
uintptr_t l = L;
__asm__ __volatile__ ("cld ; rep stosb" :"+c" (l), "+D" (dest) : "a" (0) : "memory");
#else
__asm__ __volatile__("cld ; rep stosb" : "+c"(l), "+D"(dest) : "a"(0) : "memory");
#else
memset(dest, 0, L);
#endif
#endif
}
/**
@ -837,13 +842,13 @@ public:
* @param dest Memory to zero
* @param len Size in bytes
*/
static ZT_INLINE void zero(void *dest, unsigned long len) noexcept
static ZT_INLINE void zero(void* dest, unsigned long len) noexcept
{
#if defined(ZT_ARCH_X64) && defined(__GNUC__)
__asm__ __volatile__ ("cld ; rep stosb" :"+c" (len), "+D" (dest) : "a" (0) : "memory");
#else
#if defined(ZT_ARCH_X64) && defined(__GNUC__)
__asm__ __volatile__("cld ; rep stosb" : "+c"(len), "+D"(dest) : "a"(0) : "memory");
#else
memset(dest, 0, len);
#endif
#endif
}
/**
@ -855,7 +860,7 @@ public:
* Remove `-` and `:` from a MAC address (in-place).
*
* @param mac The MAC address
*/
*/
static inline void cleanMac(std::string& mac)
{
auto start = mac.begin();
@ -865,6 +870,6 @@ public:
}
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -14,14 +14,14 @@
#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"
#include "Constants.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
#include <string>
#include <vector>
/**
* Maximum number of roots (sanity limit, okay to increase)
@ -76,69 +76,92 @@ namespace ZeroTier {
* world ID for Mars and nearby space is defined but not yet used, and a test
* world ID is provided for testing purposes.
*/
class World
{
public:
class World {
public:
/**
* World type -- do not change IDs
*/
enum Type
{
enum Type {
TYPE_NULL = 0,
TYPE_PLANET = 1, // Planets, of which there is currently one (Earth)
TYPE_MOON = 127 // Moons, which are user-created and many
TYPE_PLANET = 1, // Planets, of which there is currently one (Earth)
TYPE_MOON = 127 // Moons, which are user-created and many
};
/**
* Upstream server definition in world/moon
*/
struct Root
{
struct Root {
Identity identity;
std::vector<InetAddress> stableEndpoints;
inline bool operator==(const Root &r) const { return ((identity == r.identity)&&(stableEndpoints == r.stableEndpoints)); }
inline bool operator!=(const Root &r) const { return (!(*this == r)); }
inline bool operator<(const Root &r) const { return (identity < r.identity); } // for sorting
inline bool operator==(const Root& r) const
{
return ((identity == r.identity) && (stableEndpoints == r.stableEndpoints));
}
inline bool operator!=(const Root& r) const
{
return (! (*this == r));
}
inline bool operator<(const Root& r) const
{
return (identity < r.identity);
} // for sorting
};
/**
* Construct an empty / null World
*/
World() :
_id(0),
_ts(0),
_type(TYPE_NULL) {}
World() : _id(0), _ts(0), _type(TYPE_NULL)
{
}
/**
* @return Root servers for this world and their stable endpoints
*/
inline const std::vector<World::Root> &roots() const { return _roots; }
inline const std::vector<World::Root>& roots() const
{
return _roots;
}
/**
* @return World type: planet or moon
*/
inline Type type() const { return _type; }
inline Type type() const
{
return _type;
}
/**
* @return World unique identifier
*/
inline uint64_t id() const { return _id; }
inline uint64_t id() const
{
return _id;
}
/**
* @return World definition timestamp
*/
inline uint64_t timestamp() const { return _ts; }
inline uint64_t timestamp() const
{
return _ts;
}
/**
* @return C25519 signature
*/
inline const C25519::Signature &signature() const { return _signature; }
inline const C25519::Signature& signature() const
{
return _signature;
}
/**
* @return Public key that must sign next update
*/
inline const C25519::Public &updatesMustBeSignedBy() const { return _updatesMustBeSignedBy; }
inline const C25519::Public& updatesMustBeSignedBy() const
{
return _updatesMustBeSignedBy;
}
/**
* Check whether a world update should replace this one
@ -146,15 +169,15 @@ public:
* @param update Candidate update
* @return True if update is newer than current, matches its ID and type, and is properly signed (or if current is NULL)
*/
inline bool shouldBeReplacedBy(const World &update)
inline bool shouldBeReplacedBy(const World& update)
{
if ((_id == 0)||(_type == TYPE_NULL)) {
if ((_id == 0) || (_type == TYPE_NULL)) {
return true;
}
if ((_id == update._id)&&(_ts < update._ts)&&(_type == update._type)) {
if ((_id == update._id) && (_ts < update._ts) && (_type == update._type)) {
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
update.serialize(tmp,true);
return C25519::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature);
update.serialize(tmp, true);
return C25519::verify(_updatesMustBeSignedBy, tmp.data(), tmp.size(), update._signature);
}
return false;
}
@ -162,10 +185,12 @@ public:
/**
* @return True if this World is non-empty
*/
inline operator bool() const { return (_type != TYPE_NULL); }
inline operator bool() const
{
return (_type != TYPE_NULL);
}
template<unsigned int C>
inline void serialize(Buffer<C> &b,bool forSign = false) const
template <unsigned int C> inline void serialize(Buffer<C>& b, bool forSign = false) const
{
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -174,20 +199,20 @@ public:
b.append((uint8_t)_type);
b.append((uint64_t)_id);
b.append((uint64_t)_ts);
b.append(_updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN);
if (!forSign) {
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
b.append(_updatesMustBeSignedBy.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) {
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) {
for (std::vector<InetAddress>::const_iterator ep(r->stableEndpoints.begin()); ep != r->stableEndpoints.end(); ++ep) {
ep->serialize(b);
}
}
if (_type == TYPE_MOON) {
b.append((uint16_t)0); // no attached dictionary (for future use)
b.append((uint16_t)0); // no attached dictionary (for future use)
}
if (forSign) {
@ -195,15 +220,14 @@ public:
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
unsigned int p = startAt;
_roots.clear();
switch((Type)b[p++]) {
case TYPE_NULL: // shouldn't ever really happen in serialized data but it's not invalid
switch ((Type)b[p++]) {
case TYPE_NULL: // shouldn't ever really happen in serialized data but it's not invalid
_type = TYPE_NULL;
break;
case TYPE_PLANET:
@ -220,25 +244,25 @@ public:
p += 8;
_ts = b.template at<uint64_t>(p);
p += 8;
memcpy(_updatesMustBeSignedBy.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
memcpy(_updatesMustBeSignedBy.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);
memcpy(_signature.data, b.field(p, ZT_C25519_SIGNATURE_LEN), ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
const unsigned int numRoots = (unsigned int)b[p++];
if (numRoots > ZT_WORLD_MAX_ROOTS) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
for(unsigned int k=0;k<numRoots;++k) {
for (unsigned int k = 0; k < numRoots; ++k) {
_roots.push_back(Root());
Root &r = _roots.back();
p += r.identity.deserialize(b,p);
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 ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
for(unsigned int kk=0;kk<numStableEndpoints;++kk) {
for (unsigned int kk = 0; kk < numStableEndpoints; ++kk) {
r.stableEndpoints.push_back(InetAddress());
p += r.stableEndpoints.back().deserialize(b,p);
p += r.stableEndpoints.back().deserialize(b, p);
}
}
if (_type == TYPE_MOON) {
@ -248,8 +272,16 @@ public:
return (p - startAt);
}
inline bool operator==(const World &w) const { return ((_id == w._id)&&(_ts == w._ts)&&(memcmp(_updatesMustBeSignedBy.data,w._updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN) == 0)&&(memcmp(_signature.data,w._signature.data,ZT_C25519_SIGNATURE_LEN) == 0)&&(_roots == w._roots)&&(_type == w._type)); }
inline bool operator!=(const World &w) const { return (!(*this == w)); }
inline bool operator==(const World& w) const
{
return (
(_id == w._id) && (_ts == w._ts) && (memcmp(_updatesMustBeSignedBy.data, w._updatesMustBeSignedBy.data, ZT_C25519_PUBLIC_KEY_LEN) == 0) && (memcmp(_signature.data, w._signature.data, ZT_C25519_SIGNATURE_LEN) == 0)
&& (_roots == w._roots) && (_type == w._type));
}
inline bool operator!=(const World& w) const
{
return (! (*this == w));
}
/**
* Create a World object signed with a key pair
@ -262,7 +294,7 @@ public:
* @param signWith Key to sign this World with (can have the same public as the next-update signing key, but doesn't have to)
* @return Signed World object
*/
static inline World make(World::Type t,uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector<World::Root> &roots,const C25519::Pair &signWith)
static inline World make(World::Type t, uint64_t id, uint64_t ts, const C25519::Public& sk, const std::vector<World::Root>& roots, const C25519::Pair& signWith)
{
World w;
w._id = id;
@ -272,13 +304,13 @@ public:
w._roots = roots;
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
w.serialize(tmp,true);
w._signature = C25519::sign(signWith,tmp.data(),tmp.size());
w.serialize(tmp, true);
w._signature = C25519::sign(signWith, tmp.data(), tmp.size());
return w;
}
protected:
protected:
uint64_t _id;
uint64_t _ts;
Type _type;
@ -287,6 +319,6 @@ protected:
std::vector<Root> _roots;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,29 +11,28 @@
*/
/****/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Arp.hpp"
#include "OSUtils.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
namespace ZeroTier {
static const uint8_t ARP_REQUEST_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x01 };
static const uint8_t ARP_RESPONSE_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x02 };
static const uint8_t ARP_REQUEST_HEADER[8] = { 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01 };
static const uint8_t ARP_RESPONSE_HEADER[8] = { 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02 };
Arp::Arp() :
_cache(256),
_lastCleaned(OSUtils::now())
Arp::Arp() : _cache(256), _lastCleaned(OSUtils::now())
{
}
void Arp::addLocal(uint32_t ip,const MAC &mac)
void Arp::addLocal(uint32_t ip, const MAC& mac)
{
_ArpEntry &e = _cache[ip];
e.lastQuerySent = 0; // local IP
e.lastResponseReceived = 0; // local IP
_ArpEntry& e = _cache[ip];
e.lastQuerySent = 0; // local IP
e.lastResponseReceived = 0; // local IP
e.mac = mac;
e.local = true;
}
@ -43,7 +42,7 @@ void Arp::remove(uint32_t ip)
_cache.erase(ip);
}
uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest)
uint32_t Arp::processIncomingArp(const void* arp, unsigned int len, void* response, unsigned int& responseLen, MAC& responseDest)
{
const uint64_t now = OSUtils::now();
uint32_t ip = 0;
@ -52,25 +51,26 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
responseDest.zero();
if (len >= 28) {
if (!memcmp(arp,ARP_REQUEST_HEADER,8)) {
if (! memcmp(arp, ARP_REQUEST_HEADER, 8)) {
// Respond to ARP requests for locally-known IPs
_ArpEntry *targetEntry = _cache.get(reinterpret_cast<const uint32_t *>(arp)[6]);
if ((targetEntry)&&(targetEntry->local)) {
memcpy(response,ARP_RESPONSE_HEADER,8);
targetEntry->mac.copyTo(reinterpret_cast<uint8_t *>(response) + 8,6);
memcpy(reinterpret_cast<uint8_t *>(response) + 14,reinterpret_cast<const uint8_t *>(arp) + 24,4);
memcpy(reinterpret_cast<uint8_t *>(response) + 18,reinterpret_cast<const uint8_t *>(arp) + 8,10);
_ArpEntry* targetEntry = _cache.get(reinterpret_cast<const uint32_t*>(arp)[6]);
if ((targetEntry) && (targetEntry->local)) {
memcpy(response, ARP_RESPONSE_HEADER, 8);
targetEntry->mac.copyTo(reinterpret_cast<uint8_t*>(response) + 8, 6);
memcpy(reinterpret_cast<uint8_t*>(response) + 14, reinterpret_cast<const uint8_t*>(arp) + 24, 4);
memcpy(reinterpret_cast<uint8_t*>(response) + 18, reinterpret_cast<const uint8_t*>(arp) + 8, 10);
responseLen = 28;
responseDest.setTo(reinterpret_cast<const uint8_t *>(arp) + 8,6);
responseDest.setTo(reinterpret_cast<const uint8_t*>(arp) + 8, 6);
}
} else if (!memcmp(arp,ARP_RESPONSE_HEADER,8)) {
}
else if (! memcmp(arp, ARP_RESPONSE_HEADER, 8)) {
// Learn cache entries for remote IPs from relevant ARP replies
uint32_t responseIp = 0;
memcpy(&responseIp,reinterpret_cast<const uint8_t *>(arp) + 14,4);
_ArpEntry *queryEntry = _cache.get(responseIp);
if ((queryEntry)&&(!queryEntry->local)&&((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) {
memcpy(&responseIp, reinterpret_cast<const uint8_t*>(arp) + 14, 4);
_ArpEntry* queryEntry = _cache.get(responseIp);
if ((queryEntry) && (! queryEntry->local) && ((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) {
queryEntry->lastResponseReceived = now;
queryEntry->mac.setTo(reinterpret_cast<const uint8_t *>(arp) + 8,6);
queryEntry->mac.setTo(reinterpret_cast<const uint8_t*>(arp) + 8, 6);
ip = responseIp;
}
}
@ -78,11 +78,11 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
if ((now - _lastCleaned) >= ZT_ARP_EXPIRE) {
_lastCleaned = now;
Hashtable< uint32_t,_ArpEntry >::Iterator i(_cache);
uint32_t *k = (uint32_t *)0;
_ArpEntry *v = (_ArpEntry *)0;
while (i.next(k,v)) {
if ((!v->local)&&((now - v->lastResponseReceived) >= ZT_ARP_EXPIRE))
Hashtable<uint32_t, _ArpEntry>::Iterator i(_cache);
uint32_t* k = (uint32_t*)0;
_ArpEntry* v = (_ArpEntry*)0;
while (i.next(k, v)) {
if ((! v->local) && ((now - v->lastResponseReceived) >= ZT_ARP_EXPIRE))
_cache.erase(*k);
}
}
@ -90,27 +90,32 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
return ip;
}
MAC Arp::query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest)
MAC Arp::query(const MAC& localMac, uint32_t localIp, uint32_t targetIp, void* query, unsigned int& queryLen, MAC& queryDest)
{
const uint64_t now = OSUtils::now();
_ArpEntry &e = _cache[targetIp];
_ArpEntry& e = _cache[targetIp];
if ( ((e.mac)&&((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) ||
((!e.mac)&&((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL)) ) {
if (((e.mac) && ((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) || ((! e.mac) && ((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL))) {
e.lastQuerySent = now;
uint8_t *q = reinterpret_cast<uint8_t *>(query);
memcpy(q,ARP_REQUEST_HEADER,8); q += 8; // ARP request header information, always the same
localMac.copyTo(q,6); q += 6; // sending host MAC address
memcpy(q,&localIp,4); q += 4; // sending host IP (IP already in big-endian byte order)
memset(q,0,6); q += 6; // sending zeros for target MAC address as thats what we want to find
memcpy(q,&targetIp,4); // target IP address for resolution (IP already in big-endian byte order)
uint8_t* q = reinterpret_cast<uint8_t*>(query);
memcpy(q, ARP_REQUEST_HEADER, 8);
q += 8; // ARP request header information, always the same
localMac.copyTo(q, 6);
q += 6; // sending host MAC address
memcpy(q, &localIp, 4);
q += 4; // sending host IP (IP already in big-endian byte order)
memset(q, 0, 6);
q += 6; // sending zeros for target MAC address as thats what we want to find
memcpy(q, &targetIp, 4); // target IP address for resolution (IP already in big-endian byte order)
queryLen = 28;
if (e.mac)
queryDest = e.mac; // confirmation query, send directly to address holder
else queryDest = (uint64_t)0xffffffffffffULL; // broadcast query
} else {
queryDest = e.mac; // confirmation query, send directly to address holder
else
queryDest = (uint64_t)0xffffffffffffULL; // broadcast query
}
else {
queryLen = 0;
queryDest.zero();
}
@ -118,4 +123,4 @@ MAC Arp::query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *quer
return e.mac;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,14 +14,13 @@
#ifndef ZT_ARP_HPP
#define ZT_ARP_HPP
#include <stdint.h>
#include <utility>
#include "../node/Constants.hpp"
#include "../node/Hashtable.hpp"
#include "../node/MAC.hpp"
#include <stdint.h>
#include <utility>
/**
* Maximum possible ARP length
*
@ -67,9 +66,8 @@ namespace ZeroTier {
* This class is not thread-safe and must be guarded if used in multi-threaded
* code.
*/
class Arp
{
public:
class Arp {
public:
Arp();
/**
@ -78,7 +76,7 @@ public:
* @param mac Our local MAC address
* @param ip IP in big-endian byte order (sin_addr.s_addr)
*/
void addLocal(uint32_t ip,const MAC &mac);
void addLocal(uint32_t ip, const MAC& mac);
/**
* Delete a local IP entry or a cached ARP entry
@ -103,7 +101,7 @@ public:
* @param responseDest Destination of response, or set to null if no response
* @return IP address learned or 0 if no new IPs in cache
*/
uint32_t processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest);
uint32_t processIncomingArp(const void* arp, unsigned int len, void* response, unsigned int& responseLen, MAC& responseDest);
/**
* Get the MAC corresponding to an IP, generating a query if needed
@ -115,29 +113,30 @@ public:
* MAC returned is non-null.
*
* @param localMac Local MAC address of host interface
* @param localIp Local IP address of host interface
* @param localIp Local IP address of host interface
* @param targetIp IP to look up
* @param query Buffer for generated query -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size
* @param queryLen Length of generated query, or set to 0 if no query generated
* @param queryDest Destination of query, or set to null if no query generated
* @return MAC or 0 if no cached entry for this IP
*/
MAC query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest);
MAC query(const MAC& localMac, uint32_t localIp, uint32_t targetIp, void* query, unsigned int& queryLen, MAC& queryDest);
private:
struct _ArpEntry
{
_ArpEntry() : lastQuerySent(0),lastResponseReceived(0),mac(),local(false) {}
uint64_t lastQuerySent; // Time last query was sent or 0 for local IP
uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP
MAC mac; // MAC address of device responsible for IP or null if not known yet
bool local; // True if this is a local ARP entry
private:
struct _ArpEntry {
_ArpEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false)
{
}
uint64_t lastQuerySent; // Time last query was sent or 0 for local IP
uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP
MAC mac; // MAC address of device responsible for IP or null if not known yet
bool local; // True if this is a local ARP entry
};
Hashtable< uint32_t,_ArpEntry > _cache;
Hashtable<uint32_t, _ArpEntry> _cache;
uint64_t _lastCleaned;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

Some files were not shown because too many files have changed in this diff Show more