clang-format this branch to match dev

This commit is contained in:
Adam Ierymenko 2025-07-03 14:10:44 -04:00
parent dcb4bc5ef4
commit 5eb3cd2699
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
133 changed files with 18805 additions and 17036 deletions

View file

@ -14,162 +14,162 @@
#ifndef ZT_CONNECTION_POOL_H_ #ifndef ZT_CONNECTION_POOL_H_
#define ZT_CONNECTION_POOL_H_ #define ZT_CONNECTION_POOL_H_
#ifndef _DEBUG #ifndef _DEBUG
#define _DEBUG(x) #define _DEBUG(x)
#endif #endif
#include "../node/Metrics.hpp" #include "../node/Metrics.hpp"
#include <deque> #include <deque>
#include <set> #include <exception>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <exception> #include <set>
#include <string> #include <string>
namespace ZeroTier { namespace ZeroTier {
struct ConnectionUnavailable : std::exception { struct ConnectionUnavailable : std::exception {
char const* what() const throw() { char const* what() const throw()
return "Unable to allocate connection"; {
}; return "Unable to allocate connection";
};
}; };
class Connection { class Connection {
public: public:
virtual ~Connection() {}; virtual ~Connection() {};
}; };
class ConnectionFactory { class ConnectionFactory {
public: public:
virtual ~ConnectionFactory() {}; virtual ~ConnectionFactory() {};
virtual std::shared_ptr<Connection> create()=0; virtual std::shared_ptr<Connection> create() = 0;
}; };
struct ConnectionPoolStats { struct ConnectionPoolStats {
size_t pool_size; size_t pool_size;
size_t borrowed_size; size_t borrowed_size;
}; };
template<class T> template <class T> class ConnectionPool {
class ConnectionPool { public:
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)
ConnectionPool(size_t max_pool_size, size_t min_pool_size, std::shared_ptr<ConnectionFactory> factory) {
: m_maxPoolSize(max_pool_size) Metrics::max_pool_size += max_pool_size;
, m_minPoolSize(min_pool_size) Metrics::min_pool_size += min_pool_size;
, m_factory(factory) while (m_pool.size() < m_minPoolSize) {
{ m_pool.push_back(m_factory->create());
Metrics::max_pool_size += max_pool_size; Metrics::pool_avail++;
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() { ConnectionPoolStats get_stats()
std::unique_lock<std::mutex> lock(m_poolMutex); {
std::unique_lock<std::mutex> lock(m_poolMutex);
ConnectionPoolStats stats; ConnectionPoolStats stats;
stats.pool_size = m_pool.size(); stats.pool_size = m_pool.size();
stats.borrowed_size = m_borrowed.size(); stats.borrowed_size = m_borrowed.size();
return stats; return stats;
}; };
~ConnectionPool() { ~ConnectionPool() {};
};
/** /**
* Borrow * Borrow
* *
* Borrow a connection for temporary use * 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. * 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 * @retval a shared_ptr to the connection object
*/ */
std::shared_ptr<T> borrow() { std::shared_ptr<T> borrow()
std::unique_lock<std::mutex> l(m_poolMutex); {
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++;
}
if(m_pool.size()==0){ while ((m_pool.size() + m_borrowed.size()) < m_minPoolSize) {
std::shared_ptr<Connection> conn = m_factory->create();
if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) { m_pool.push_back(conn);
try { Metrics::pool_avail++;
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();
}
}
// Take one off the front if (m_pool.size() == 0) {
std::shared_ptr<Connection> conn = m_pool.front(); if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
m_pool.pop_front(); try {
Metrics::pool_avail--; std::shared_ptr<Connection> conn = m_factory->create();
// Add it to the borrowed list m_borrowed.insert(conn);
m_borrowed.insert(conn); Metrics::pool_in_use++;
Metrics::pool_in_use++; return std::static_pointer_cast<T>(conn);
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();
}
}
/** // Take one off the front
* Unborrow a connection std::shared_ptr<Connection> conn = m_pool.front();
* m_pool.pop_front();
* 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). Metrics::pool_avail--;
* @param the connection // Add it to the borrowed list
*/ m_borrowed.insert(conn);
void unborrow(std::shared_ptr<T> conn) { Metrics::pool_in_use++;
// Lock return std::static_pointer_cast<T>(conn);
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) { * Unborrow a connection
Metrics::pool_avail++; *
m_pool.push_back(conn); * 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
}; */
protected: void unborrow(std::shared_ptr<T> conn)
size_t m_maxPoolSize; {
size_t m_minPoolSize; // Lock
std::shared_ptr<ConnectionFactory> m_factory; std::unique_lock<std::mutex> lock(m_poolMutex);
std::deque<std::shared_ptr<Connection> > m_pool; m_borrowed.erase(conn);
std::set<std::shared_ptr<Connection> > m_borrowed; Metrics::pool_in_use--;
std::mutex m_poolMutex; 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 #endif

View file

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

View file

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

View file

@ -15,56 +15,54 @@
namespace ZeroTier { namespace ZeroTier {
DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener) DBMirrorSet::DBMirrorSet(DB::ChangeListener* listener) : _listener(listener), _running(true), _syncCheckerThread(), _dbs(), _dbs_l()
: _listener(listener)
, _running(true)
, _syncCheckerThread()
, _dbs()
, _dbs_l()
{ {
_syncCheckerThread = std::thread([this]() { _syncCheckerThread = std::thread([this]() {
for(;;) { for (;;) {
for(int i=0;i<120;++i) { // 1 minute delay between checks for (int i = 0; i < 120; ++i) { // 1 minute delay between checks
if (!_running) if (! _running)
return; return;
std::this_thread::sleep_for(std::chrono::milliseconds(500)); 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); std::unique_lock<std::shared_mutex> l(_dbs_l);
if (_dbs.size() <= 1) 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; dbs = _dbs;
} }
for(auto db=dbs.begin();db!=dbs.end();++db) { 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) { (*db)->each([&dbs, &db](uint64_t networkId, const nlohmann::json& network, uint64_t memberId, const nlohmann::json& member) {
try { try {
if (network.is_object()) { if (network.is_object()) {
if (memberId == 0) { 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()) { if (db->get() != db2->get()) {
nlohmann::json nw2; 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; 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()) { if (db->get() != db2->get()) {
nlohmann::json nw2,m2; nlohmann::json nw2, m2;
if ((!(*db2)->get(networkId,nw2,memberId,m2))||((m2.is_object())&&(OSUtils::jsonInt(m2["revision"],0) < OSUtils::jsonInt(member["revision"],0)))) { if ((! (*db2)->get(networkId, nw2, memberId, m2)) || ((m2.is_object()) && (OSUtils::jsonInt(m2["revision"], 0) < OSUtils::jsonInt(member["revision"], 0)))) {
m2 = member; 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 bool DBMirrorSet::hasNetwork(const uint64_t networkId) const
{ {
std::shared_lock<std::shared_mutex> l(_dbs_l); 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)) if ((*d)->hasNetwork(networkId))
return true; return true;
} }
return false; 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); 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)->get(networkId,network)) { if ((*d)->get(networkId, network)) {
return true; return true;
} }
} }
return false; 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); 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)->get(networkId,network,memberId,member)) if ((*d)->get(networkId, network, memberId, member))
return true; return true;
} }
return false; 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); 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)->get(networkId,network,memberId,member,info)) if ((*d)->get(networkId, network, memberId, member, info))
return true; return true;
} }
return false; 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); 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)->get(networkId,network,members)) if ((*d)->get(networkId, network, members))
return true; return true;
} }
return false; 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); 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); AuthInfo info = (*d)->getSSOAuthInfo(member, redirectURL);
if (info.enabled) { if (info.enabled) {
return info; return info;
@ -140,10 +138,10 @@ AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::st
return AuthInfo(); 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); 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); (*d)->networks(networks);
} }
} }
@ -152,7 +150,7 @@ bool DBMirrorSet::waitForReady()
{ {
bool r = false; bool r = false;
std::shared_lock<std::shared_mutex> l(_dbs_l); 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(); r |= (*d)->waitForReady();
} }
return r; return r;
@ -161,30 +159,31 @@ bool DBMirrorSet::waitForReady()
bool DBMirrorSet::isReady() bool DBMirrorSet::isReady()
{ {
std::shared_lock<std::shared_mutex> l(_dbs_l); 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)->isReady()) if (! (*d)->isReady())
return false; return false;
} }
return true; 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); std::unique_lock<std::shared_mutex> l(_dbs_l);
dbs = _dbs; dbs = _dbs;
} }
if (notifyListeners) { if (notifyListeners) {
for(auto d=dbs.begin();d!=dbs.end();++d) { for (auto d = dbs.begin(); d != dbs.end(); ++d) {
if ((*d)->save(record,true)) if ((*d)->save(record, true))
return true; return true;
} }
return false; return false;
} else { }
else {
bool modified = false; bool modified = false;
for(auto d=dbs.begin();d!=dbs.end();++d) { for (auto d = dbs.begin(); d != dbs.end(); ++d) {
modified |= (*d)->save(record,false); modified |= (*d)->save(record, false);
} }
return modified; return modified;
} }
@ -193,54 +192,54 @@ bool DBMirrorSet::save(nlohmann::json &record,bool notifyListeners)
void DBMirrorSet::eraseNetwork(const uint64_t networkId) void DBMirrorSet::eraseNetwork(const uint64_t networkId)
{ {
std::unique_lock<std::shared_mutex> l(_dbs_l); 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); (*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); 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)->eraseMember(networkId,memberId); (*d)->eraseMember(networkId, memberId);
} }
} }
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)
{ {
std::shared_lock<std::shared_mutex> l(_dbs_l); 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)->nodeIsOnline(networkId,memberId,physicalAddress); (*d)->nodeIsOnline(networkId, memberId, physicalAddress);
} }
} }
void DBMirrorSet::onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network) void DBMirrorSet::onNetworkUpdate(const void* db, uint64_t networkId, const nlohmann::json& network)
{ {
nlohmann::json record(network); nlohmann::json record(network);
std::unique_lock<std::shared_mutex> l(_dbs_l); 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) { 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); nlohmann::json record(member);
std::unique_lock<std::shared_mutex> l(_dbs_l); 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) { 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,58 +16,57 @@
#include "DB.hpp" #include "DB.hpp"
#include <vector>
#include <memory> #include <memory>
#include <shared_mutex>
#include <set> #include <set>
#include <shared_mutex>
#include <thread> #include <thread>
#include <vector>
namespace ZeroTier { namespace ZeroTier {
class DBMirrorSet : public DB::ChangeListener class DBMirrorSet : public DB::ChangeListener {
{ public:
public: DBMirrorSet(DB::ChangeListener* listener);
DBMirrorSet(DB::ChangeListener *listener);
virtual ~DBMirrorSet(); virtual ~DBMirrorSet();
bool hasNetwork(const uint64_t networkId) const; 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);
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);
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, 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, std::vector<nlohmann::json>& members);
void networks(std::set<uint64_t> &networks); void networks(std::set<uint64_t>& networks);
bool waitForReady(); bool waitForReady();
bool isReady(); bool isReady();
bool save(nlohmann::json &record,bool notifyListeners); bool save(nlohmann::json& record, bool notifyListeners);
void eraseNetwork(const uint64_t networkId); void eraseNetwork(const uint64_t networkId);
void eraseMember(const uint64_t networkId,const uint64_t memberId); void eraseMember(const uint64_t networkId, const uint64_t memberId);
void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress); void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress);
// These are called by various DB instances when changes occur. // 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 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 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 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); db->addListener(this);
std::unique_lock<std::shared_mutex> l(_dbs_l); std::unique_lock<std::shared_mutex> l(_dbs_l);
_dbs.push_back(db); _dbs.push_back(db);
} }
private: private:
DB::ChangeListener *const _listener; DB::ChangeListener* const _listener;
std::atomic_bool _running; std::atomic_bool _running;
std::thread _syncCheckerThread; std::thread _syncCheckerThread;
std::vector< std::shared_ptr< DB > > _dbs; std::vector<std::shared_ptr<DB> > _dbs;
mutable std::shared_mutex _dbs_l; mutable std::shared_mutex _dbs_l;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -14,112 +14,109 @@
#ifndef ZT_SQLITENETWORKCONTROLLER_HPP #ifndef ZT_SQLITENETWORKCONTROLLER_HPP
#define ZT_SQLITENETWORKCONTROLLER_HPP #define ZT_SQLITENETWORKCONTROLLER_HPP
#include <stdint.h> #include "../node/Address.hpp"
#include <string>
#include <map>
#include <vector>
#include <set>
#include <list>
#include <thread>
#include <unordered_map>
#include <atomic>
#include "../node/Constants.hpp" #include "../node/Constants.hpp"
#include "../node/InetAddress.hpp"
#include "../node/NetworkController.hpp" #include "../node/NetworkController.hpp"
#include "../node/Utils.hpp" #include "../node/Utils.hpp"
#include "../node/Address.hpp" #include "../osdep/BlockingQueue.hpp"
#include "../node/InetAddress.hpp"
#include "../osdep/OSUtils.hpp" #include "../osdep/OSUtils.hpp"
#include "../osdep/Thread.hpp" #include "../osdep/Thread.hpp"
#include "../osdep/BlockingQueue.hpp"
#include <nlohmann/json.hpp>
#include <cpp-httplib/httplib.h>
#include "DB.hpp" #include "DB.hpp"
#include "DBMirrorSet.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 { namespace ZeroTier {
class Node; class Node;
struct RedisConfig; struct RedisConfig;
class EmbeddedNetworkController : public NetworkController,public DB::ChangeListener class EmbeddedNetworkController
{ : public NetworkController
public: , public DB::ChangeListener {
public:
/** /**
* @param node Parent node * @param node Parent node
* @param dbPath Database path (file path or database credentials) * @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 ~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( virtual void request(uint64_t nwid, const InetAddress& fromAddr, uint64_t requestPacketId, const Identity& identity, const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY>& metaData);
uint64_t nwid,
const InetAddress &fromAddr,
uint64_t requestPacketId,
const Identity &identity,
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
void configureHTTPControlPlane( void configureHTTPControlPlane(httplib::Server& s, httplib::Server& sV6, const std::function<void(const httplib::Request&, httplib::Response&, std::string)>);
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 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 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 onNetworkMemberDeauthorize(const void* db, uint64_t networkId, uint64_t memberId);
private: private:
void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData); 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 _startThreads();
void _ssoExpiryThread(); 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 nwid;
uint64_t requestPacketId; uint64_t requestPacketId;
InetAddress fromAddr; InetAddress fromAddr;
Identity identity; Identity identity;
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> metaData; Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> metaData;
enum { enum { RQENTRY_TYPE_REQUEST = 0 } type;
RQENTRY_TYPE_REQUEST = 0
} type;
}; };
struct _MemberStatusKey struct _MemberStatusKey {
{ _MemberStatusKey() : networkId(0), nodeId(0)
_MemberStatusKey() : networkId(0),nodeId(0) {} {
_MemberStatusKey(const uint64_t nwid,const uint64_t nid) : networkId(nwid),nodeId(nid) {} }
_MemberStatusKey(const uint64_t nwid, const uint64_t nid) : networkId(nwid), nodeId(nid)
{
}
uint64_t networkId; uint64_t networkId;
uint64_t nodeId; uint64_t nodeId;
inline bool operator==(const _MemberStatusKey &k) const { return ((k.networkId == networkId)&&(k.nodeId == nodeId)); } inline bool operator==(const _MemberStatusKey& k) const
inline bool operator<(const _MemberStatusKey &k) const { return (k.networkId < networkId) || ((k.networkId == networkId)&&(k.nodeId < nodeId)); } {
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 struct _MemberStatus {
{ _MemberStatus() : lastRequestTime(0), authenticationExpiryTime(-1), vMajor(-1), vMinor(-1), vRev(-1), vProto(-1)
_MemberStatus() : lastRequestTime(0),authenticationExpiryTime(-1),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {} {
}
int64_t lastRequestTime; int64_t lastRequestTime;
int64_t authenticationExpiryTime; int64_t authenticationExpiryTime;
int vMajor,vMinor,vRev,vProto; int vMajor, vMinor, vRev, vProto;
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> lastRequestMetaData; Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> lastRequestMetaData;
Identity identity; 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 struct _MemberStatusHash {
{ inline std::size_t operator()(const _MemberStatusKey& networkIdNodeId) const
inline std::size_t operator()(const _MemberStatusKey &networkIdNodeId) const
{ {
return (std::size_t)(networkIdNodeId.networkId + networkIdNodeId.nodeId); return (std::size_t)(networkIdNodeId.networkId + networkIdNodeId.nodeId);
} }
@ -127,26 +124,26 @@ private:
const int64_t _startTime; const int64_t _startTime;
int _listenPort; int _listenPort;
Node *const _node; Node* const _node;
std::string _ztPath; std::string _ztPath;
std::string _path; std::string _path;
Identity _signingId; Identity _signingId;
std::string _signingIdAddressString; std::string _signingIdAddressString;
NetworkController::Sender *_sender; NetworkController::Sender* _sender;
DBMirrorSet _db; DBMirrorSet _db;
BlockingQueue< _RQEntry * > _queue; BlockingQueue<_RQEntry*> _queue;
std::vector<std::thread> _threads; std::vector<std::thread> _threads;
std::mutex _threads_l; std::mutex _threads_l;
std::unordered_map< _MemberStatusKey,_MemberStatus,_MemberStatusHash > _memberStatus; std::unordered_map<_MemberStatusKey, _MemberStatus, _MemberStatusHash> _memberStatus;
std::mutex _memberStatus_l; std::mutex _memberStatus_l;
std::set< std::pair<int64_t, _MemberStatusKey> > _expiringSoon; std::set<std::pair<int64_t, _MemberStatusKey> > _expiringSoon;
std::mutex _expiringSoon_l; std::mutex _expiringSoon_l;
RedisConfig *_rc; RedisConfig* _rc;
std::string _ssoRedirectURL; std::string _ssoRedirectURL;
bool _ssoExpiryRunning; bool _ssoExpiryRunning;
@ -154,30 +151,30 @@ private:
#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK #ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK
prometheus::simpleapi::benchmark_family_t _member_status_lookup; 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::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::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::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::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::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::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::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::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::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::benchmark_family_t _send_netconf;
prometheus::simpleapi::counter_family_t _send_netconf_count; prometheus::simpleapi::counter_family_t _send_netconf_count;
#endif #endif
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

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

View file

@ -16,32 +16,30 @@
#include "DB.hpp" #include "DB.hpp"
namespace ZeroTier namespace ZeroTier {
{
class FileDB : public DB class FileDB : public DB {
{ public:
public: FileDB(const char* path);
FileDB(const char *path);
virtual ~FileDB(); virtual ~FileDB();
virtual bool waitForReady(); virtual bool waitForReady();
virtual bool isReady(); 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 eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId); 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);
protected: protected:
std::string _path; std::string _path;
std::string _networksPath; std::string _networksPath;
std::string _tracePath; std::string _tracePath;
std::thread _onlineUpdateThread; 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; std::mutex _online_l;
bool _running; bool _running;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

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

View file

@ -16,19 +16,18 @@
#include "DB.hpp" #include "DB.hpp"
#include <atomic>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <atomic>
namespace ZeroTier { namespace ZeroTier {
/** /**
* DB implementation for controller that stores data in LF * DB implementation for controller that stores data in LF
*/ */
class LFDB : public DB class LFDB : public DB {
{ public:
public:
/** /**
* @param myId This controller's identity * @param myId This controller's identity
* @param path Base path for ZeroTier node itself * @param path Base path for ZeroTier node itself
@ -38,44 +37,40 @@ public:
* @param lfNodePort LF node http (not https) port * @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!) * @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 ~LFDB();
virtual bool waitForReady(); virtual bool waitForReady();
virtual bool isReady(); 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 eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId); 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);
protected: protected:
const Identity _myId; const Identity _myId;
std::string _lfOwnerPrivate,_lfOwnerPublic; std::string _lfOwnerPrivate, _lfOwnerPublic;
std::string _lfNodeHost; std::string _lfNodeHost;
int _lfNodePort; int _lfNodePort;
struct _MemberState struct _MemberState {
{ _MemberState() : lastOnlineAddress(), lastOnlineTime(0), dirty(false), lastOnlineDirty(false)
_MemberState() : {
lastOnlineAddress(), }
lastOnlineTime(0),
dirty(false),
lastOnlineDirty(false) {}
InetAddress lastOnlineAddress; InetAddress lastOnlineAddress;
int64_t lastOnlineTime; int64_t lastOnlineTime;
bool dirty; bool dirty;
bool lastOnlineDirty; bool lastOnlineDirty;
}; };
struct _NetworkState struct _NetworkState {
{ _NetworkState() : members(), dirty(false)
_NetworkState() : {
members(), }
dirty(false) {} std::unordered_map<uint64_t, _MemberState> members;
std::unordered_map<uint64_t,_MemberState> members;
bool dirty; bool dirty;
}; };
std::unordered_map<uint64_t,_NetworkState> _state; std::unordered_map<uint64_t, _NetworkState> _state;
std::mutex _state_l; std::mutex _state_l;
std::atomic_bool _running; std::atomic_bool _running;
@ -84,6 +79,6 @@ protected:
bool _storeOnlineState; bool _storeOnlineState;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -20,78 +20,81 @@
#define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4 #define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4
#include "../node/Metrics.hpp"
#include "ConnectionPool.hpp" #include "ConnectionPool.hpp"
#include <pqxx/pqxx>
#include <memory> #include <memory>
#include <pqxx/pqxx>
#include <redis++/redis++.h> #include <redis++/redis++.h>
#include "../node/Metrics.hpp"
extern "C" { extern "C" {
typedef struct pg_conn PGconn; typedef struct pg_conn PGconn;
} }
namespace smeeclient { namespace smeeclient {
struct SmeeClient; struct SmeeClient;
} }
namespace ZeroTier { namespace ZeroTier {
struct RedisConfig; struct RedisConfig;
class PostgresConnection : public Connection { class PostgresConnection : public Connection {
public: public:
virtual ~PostgresConnection() { virtual ~PostgresConnection()
{
} }
std::shared_ptr<pqxx::connection> c; std::shared_ptr<pqxx::connection> c;
int a; int a;
}; };
class PostgresConnFactory : public ConnectionFactory { class PostgresConnFactory : public ConnectionFactory {
public: public:
PostgresConnFactory(std::string &connString) PostgresConnFactory(std::string& connString) : m_connString(connString)
: m_connString(connString)
{ {
} }
virtual std::shared_ptr<Connection> create() { virtual std::shared_ptr<Connection> create()
{
Metrics::conn_counter++; Metrics::conn_counter++;
auto c = std::shared_ptr<PostgresConnection>(new PostgresConnection()); auto c = std::shared_ptr<PostgresConnection>(new PostgresConnection());
c->c = std::make_shared<pqxx::connection>(m_connString); c->c = std::make_shared<pqxx::connection>(m_connString);
return std::static_pointer_cast<Connection>(c); return std::static_pointer_cast<Connection>(c);
} }
private:
private:
std::string m_connString; std::string m_connString;
}; };
class PostgreSQL; class PostgreSQL;
class MemberNotificationReceiver : public pqxx::notification_receiver { class MemberNotificationReceiver : public pqxx::notification_receiver {
public: public:
MemberNotificationReceiver(PostgreSQL *p, pqxx::connection &c, const std::string &channel); MemberNotificationReceiver(PostgreSQL* p, pqxx::connection& c, const std::string& channel);
virtual ~MemberNotificationReceiver() { virtual ~MemberNotificationReceiver()
{
fprintf(stderr, "MemberNotificationReceiver destroyed\n"); fprintf(stderr, "MemberNotificationReceiver destroyed\n");
} }
virtual void operator() (const std::string &payload, int backendPid); virtual void operator()(const std::string& payload, int backendPid);
private:
PostgreSQL *_psql; private:
PostgreSQL* _psql;
}; };
class NetworkNotificationReceiver : public pqxx::notification_receiver { class NetworkNotificationReceiver : public pqxx::notification_receiver {
public: public:
NetworkNotificationReceiver(PostgreSQL *p, pqxx::connection &c, const std::string &channel); NetworkNotificationReceiver(PostgreSQL* p, pqxx::connection& c, const std::string& channel);
virtual ~NetworkNotificationReceiver() { virtual ~NetworkNotificationReceiver()
{
fprintf(stderr, "NetworkNotificationReceiver destroyed\n"); fprintf(stderr, "NetworkNotificationReceiver destroyed\n");
}; };
virtual void operator() (const std::string &payload, int packend_pid); virtual void operator()(const std::string& payload, int packend_pid);
private:
PostgreSQL *_psql; private:
PostgreSQL* _psql;
}; };
/** /**
@ -100,36 +103,40 @@ private:
* This is for use with ZeroTier Central. Others are free to build and use it * 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. * but be aware that we might change it at any time.
*/ */
class PostgreSQL : public DB class PostgreSQL : public DB {
{
friend class MemberNotificationReceiver; friend class MemberNotificationReceiver;
friend class NetworkNotificationReceiver; friend class NetworkNotificationReceiver;
public:
PostgreSQL(const Identity &myId, const char *path, int listenPort, RedisConfig *rc); public:
PostgreSQL(const Identity& myId, const char* path, int listenPort, RedisConfig* rc);
virtual ~PostgreSQL(); virtual ~PostgreSQL();
virtual bool waitForReady(); virtual bool waitForReady();
virtual bool isReady(); 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 eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId); 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);
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL); virtual AuthInfo getSSOAuthInfo(const nlohmann::json& member, const std::string& redirectURL);
protected: protected:
struct _PairHasher struct _PairHasher {
{ inline std::size_t operator()(const std::pair<uint64_t, uint64_t>& p) const
inline std::size_t operator()(const std::pair<uint64_t,uint64_t> &p) const { return (std::size_t)(p.first ^ p.second); } {
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); 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); DB::_networkChanged(old, networkConfig, notifyListeners);
} }
private: private:
void initializeNetworks(); void initializeNetworks();
void initializeMembers(); void initializeMembers();
void heartbeat(); void heartbeat();
@ -145,16 +152,12 @@ private:
void onlineNotificationThread(); void onlineNotificationThread();
void onlineNotification_Postgres(); void onlineNotification_Postgres();
void onlineNotification_Redis(); void onlineNotification_Redis();
uint64_t _doRedisUpdate(sw::redis::Transaction &tx, std::string &controllerId, uint64_t _doRedisUpdate(sw::redis::Transaction& tx, std::string& controllerId, std::unordered_map<std::pair<uint64_t, uint64_t>, std::pair<int64_t, InetAddress>, _PairHasher>& lastOnline);
std::unordered_map< std::pair<uint64_t,uint64_t>,std::pair<int64_t,InetAddress>,_PairHasher > &lastOnline);
void configureSmee(); void configureSmee();
void notifyNewMember(const std::string &networkID, const std::string &memberID); void notifyNewMember(const std::string& networkID, const std::string& memberID);
enum OverrideMode { enum OverrideMode { ALLOW_PGBOUNCER_OVERRIDE = 0, NO_OVERRIDE = 1 };
ALLOW_PGBOUNCER_OVERRIDE = 0,
NO_OVERRIDE = 1
};
std::shared_ptr<ConnectionPool<PostgresConnection> > _pool; std::shared_ptr<ConnectionPool<PostgresConnection> > _pool;
@ -163,7 +166,7 @@ private:
std::string _myAddressStr; std::string _myAddressStr;
std::string _connString; std::string _connString;
BlockingQueue< std::pair<nlohmann::json,bool> > _commitQueue; BlockingQueue<std::pair<nlohmann::json, bool> > _commitQueue;
std::thread _heartbeatThread; std::thread _heartbeatThread;
std::thread _membersDbWatcher; std::thread _membersDbWatcher;
@ -171,7 +174,7 @@ private:
std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS]; std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS];
std::thread _onlineNotificationThread; std::thread _onlineNotificationThread;
std::unordered_map< std::pair<uint64_t,uint64_t>,std::pair<int64_t,InetAddress>,_PairHasher > _lastOnline; std::unordered_map<std::pair<uint64_t, uint64_t>, std::pair<int64_t, InetAddress>, _PairHasher> _lastOnline;
mutable std::mutex _lastOnline_l; mutable std::mutex _lastOnline_l;
mutable std::mutex _readyLock; mutable std::mutex _readyLock;
@ -181,16 +184,16 @@ private:
int _listenPort; int _listenPort;
uint8_t _ssoPsk[48]; uint8_t _ssoPsk[48];
RedisConfig *_rc; RedisConfig* _rc;
std::shared_ptr<sw::redis::Redis> _redis; std::shared_ptr<sw::redis::Redis> _redis;
std::shared_ptr<sw::redis::RedisCluster> _cluster; std::shared_ptr<sw::redis::RedisCluster> _cluster;
bool _redisMemberStatus; bool _redisMemberStatus;
smeeclient::SmeeClient *_smee; smeeclient::SmeeClient* _smee;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif // ZT_CONTROLLER_LIBPQ_HPP #endif // ZT_CONTROLLER_LIBPQ_HPP
#endif // ZT_CONTROLLER_USE_LIBPQ #endif // ZT_CONTROLLER_USE_LIBPQ

View file

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

View file

@ -11,9 +11,10 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "Constants.hpp"
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wstrict-aliasing" #pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif #endif
@ -31,40 +32,40 @@ namespace ZeroTier {
namespace { namespace {
#define s_bmul32(N, x, y, rh, rl) \ #define s_bmul32(N, x, y, rh, rl) \
uint32_t x0t_##N = (x) & 0x11111111U; \ uint32_t x0t_##N = (x) & 0x11111111U; \
uint32_t x1t_##N = (x) & 0x22222222U; \ uint32_t x1t_##N = (x) & 0x22222222U; \
uint32_t x2t_##N = (x) & 0x44444444U; \ uint32_t x2t_##N = (x) & 0x44444444U; \
uint32_t x3t_##N = (x) & 0x88888888U; \ uint32_t x3t_##N = (x) & 0x88888888U; \
uint32_t y0t_##N = (y) & 0x11111111U; \ uint32_t y0t_##N = (y) & 0x11111111U; \
uint32_t y1t_##N = (y) & 0x22222222U; \ uint32_t y1t_##N = (y) & 0x22222222U; \
uint32_t y2t_##N = (y) & 0x44444444U; \ uint32_t y2t_##N = (y) & 0x44444444U; \
uint32_t y3t_##N = (y) & 0x88888888U; \ 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 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 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; \ 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; \ z0t_##N |= z1t_##N; \
z2t_##N |= z0t_##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); \ 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); \ (rh) = (uint32_t)(zt_##N >> 32U); \
(rl) = (uint32_t)zt_##N; (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 hhh = (uint32_t)(hh >> 32U);
uint32_t hhl = (uint32_t)hh; uint32_t hhl = (uint32_t)hh;
uint32_t hlh = (uint32_t)(hl >> 32U); uint32_t hlh = (uint32_t)(hl >> 32U);
uint32_t hll = (uint32_t)hl; uint32_t hll = (uint32_t)hl;
uint32_t hhXlh = hhh ^hlh; uint32_t hhXlh = hhh ^ hlh;
uint32_t hhXll = hhl ^hll; uint32_t hhXll = hhl ^ hll;
uint64_t yl = Utils::ntoh(y0); uint64_t yl = Utils::ntoh(y0);
uint64_t yh = Utils::ntoh(y1); uint64_t yh = Utils::ntoh(y1);
uint32_t cilh = (uint32_t)(yh >> 32U); uint32_t cilh = (uint32_t)(yh >> 32U);
uint32_t cill = (uint32_t)yh; uint32_t cill = (uint32_t)yh;
uint32_t cihh = (uint32_t)(yl >> 32U); uint32_t cihh = (uint32_t)(yl >> 32U);
uint32_t cihl = (uint32_t)yl; uint32_t cihl = (uint32_t)yl;
uint32_t cihXlh = cihh ^cilh; uint32_t cihXlh = cihh ^ cilh;
uint32_t cihXll = cihl ^cill; uint32_t cihXll = cihl ^ cill;
uint32_t aah, aal, abh, abl, ach, acl; uint32_t aah, aal, abh, abl, ach, acl;
s_bmul32(M0, cihh, hhh, aah, aal); s_bmul32(M0, cihh, hhh, aah, aal);
s_bmul32(M1, cihl, hhl, abh, abl); 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; cbh ^= bbh ^ abh;
cbl ^= bbl ^ abl; cbl ^= bbl ^ abl;
uint64_t zhh = ((uint64_t)aah << 32U) | aal; uint64_t zhh = ((uint64_t)aah << 32U) | aal;
uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^(((uint64_t)cah << 32U) | cal); 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 zlh = (((uint64_t)bah << 32U) | bal) ^ (((uint64_t)cbh << 32U) | cbl);
uint64_t zll = ((uint64_t)bbh << 32U) | bbl; uint64_t zll = ((uint64_t)bbh << 32U) | bbl;
zhh = zhh << 1U | zhl >> 63U; zhh = zhh << 1U | zhl >> 63U;
zhl = zhl << 1U | zlh >> 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); 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; _len += len;
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
@ -120,14 +121,14 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
p_aesNIUpdate(in, len); p_aesNIUpdate(in, len);
return; return;
} }
#endif // ZT_AES_AESNI #endif // ZT_AES_AESNI
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
if (Utils::ARMCAP.pmull) { if (Utils::ARMCAP.pmull) {
p_armUpdate(in, len); p_armUpdate(in, len);
return; return;
} }
#endif // ZT_AES_NEON #endif // ZT_AES_NEON
const uint64_t h0 = _aes.p_k.sw.h[0]; const uint64_t h0 = _aes.p_k.sw.h[0];
const uint64_t h1 = _aes.p_k.sw.h[1]; 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) { if (_rp) {
for (;;) { for (;;) {
if (!len) { if (! len) {
return; return;
} }
--len; --len;
_r[_rp++] = *(in++); _r[_rp++] = *(in++);
if (_rp == 16) { if (_rp == 16) {
y0 ^= Utils::loadMachineEndian< uint64_t >(_r); y0 ^= Utils::loadMachineEndian<uint64_t>(_r);
y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8); y1 ^= Utils::loadMachineEndian<uint64_t>(_r + 8);
s_gfmul(h0, h1, y0, y1); s_gfmul(h0, h1, y0, y1);
break; break;
} }
@ -151,8 +152,8 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
} }
while (len >= 16) { while (len >= 16) {
y0 ^= Utils::loadMachineEndian< uint64_t >(in); y0 ^= Utils::loadMachineEndian<uint64_t>(in);
y1 ^= Utils::loadMachineEndian< uint64_t >(in + 8); y1 ^= Utils::loadMachineEndian<uint64_t>(in + 8);
in += 16; in += 16;
s_gfmul(h0, h1, y0, y1); s_gfmul(h0, h1, y0, y1);
len -= 16; 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) { for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[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 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); p_aesNIFinish(tag);
return; return;
} }
#endif // ZT_AES_AESNI #endif // ZT_AES_AESNI
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
if (Utils::ARMCAP.pmull) { if (Utils::ARMCAP.pmull) {
p_armFinish(tag); p_armFinish(tag);
return; return;
} }
#endif // ZT_AES_NEON #endif // ZT_AES_NEON
const uint64_t h0 = _aes.p_k.sw.h[0]; const uint64_t h0 = _aes.p_k.sw.h[0];
const uint64_t h1 = _aes.p_k.sw.h[1]; 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) { while (_rp < 16) {
_r[_rp++] = 0; _r[_rp++] = 0;
} }
y0 ^= Utils::loadMachineEndian< uint64_t >(_r); y0 ^= Utils::loadMachineEndian<uint64_t>(_r);
y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8); y1 ^= Utils::loadMachineEndian<uint64_t>(_r + 8);
s_gfmul(h0, h1, y0, y1); 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); s_gfmul(h0, h1, y0, y1);
uint64_t iv2[2]; uint64_t iv2[2];
Utils::copy< 12 >(iv2, _iv); Utils::copy<12>(iv2, _iv);
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
reinterpret_cast<uint32_t *>(iv2)[3] = 0x00000001; reinterpret_cast<uint32_t*>(iv2)[3] = 0x00000001;
#else #else
reinterpret_cast<uint32_t *>(iv2)[3] = 0x01000000; reinterpret_cast<uint32_t*>(iv2)[3] = 0x01000000;
#endif #endif
_aes.encrypt(iv2, iv2); _aes.encrypt(iv2, iv2);
Utils::storeMachineEndian< uint64_t >(tag, iv2[0] ^ y0); Utils::storeMachineEndian<uint64_t>(tag, iv2[0] ^ y0);
Utils::storeMachineEndian< uint64_t >(tag + 8, iv2[1] ^ y1); Utils::storeMachineEndian<uint64_t>(tag + 8, iv2[1] ^ y1);
} }
// AES-CTR ------------------------------------------------------------------------------------------------------------ // 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); const uint8_t* in = reinterpret_cast<const uint8_t*>(input);
uint8_t *out = _out; uint8_t* out = _out;
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) { if (likely(Utils::CPUID.aes)) {
p_aesNICrypt(in, out, len); p_aesNICrypt(in, out, len);
return; return;
} }
#endif // ZT_AES_AESNI #endif // ZT_AES_AESNI
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
if (Utils::ARMCAP.aes) { if (Utils::ARMCAP.aes) {
p_armCrypt(in, out, len); p_armCrypt(in, out, len);
return; return;
} }
#endif // ZT_AES_NEON #endif // ZT_AES_NEON
uint64_t keyStream[2]; 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; unsigned int totalLen = _len;
if ((totalLen & 15U)) { if ((totalLen & 15U)) {
for (;;) { for (;;) {
if (!len) { if (! len) {
_len = (totalLen + len); _len = (totalLen + len);
return; return;
} }
--len; --len;
out[totalLen++] = *(in++); out[totalLen++] = *(in++);
if (!(totalLen & 15U)) { if (! (totalLen & 15U)) {
_aes.p_encryptSW(reinterpret_cast<const uint8_t *>(_ctr), reinterpret_cast<uint8_t *>(keyStream)); _aes.p_encryptSW(reinterpret_cast<const uint8_t*>(_ctr), reinterpret_cast<uint8_t*>(keyStream));
reinterpret_cast<uint32_t *>(_ctr)[3] = Utils::hton(++ctr); reinterpret_cast<uint32_t*>(_ctr)[3] = Utils::hton(++ctr);
uint8_t *outblk = out + (totalLen - 16); uint8_t* outblk = out + (totalLen - 16);
for (int i = 0; i < 16; ++i) { for (int i = 0; i < 16; ++i) {
outblk[i] ^= reinterpret_cast<uint8_t *>(keyStream)[i]; outblk[i] ^= reinterpret_cast<uint8_t*>(keyStream)[i];
} }
break; break;
} }
@ -262,10 +263,10 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
_len = (totalLen + len); _len = (totalLen + len);
if (likely(len >= 16)) { if (likely(len >= 16)) {
const uint32_t *const restrict rk = _aes.p_k.sw.ek; 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 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 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 ctr2rk2 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[2]) ^ rk[2];
const uint32_t m8 = 0x000000ff; const uint32_t m8 = 0x000000ff;
const uint32_t m8_8 = 0x0000ff00; const uint32_t m8_8 = 0x0000ff00;
const uint32_t m8_16 = 0x00ff0000; const uint32_t m8_16 = 0x00ff0000;
@ -278,8 +279,8 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
s2 = ctr2rk2; s2 = ctr2rk2;
s3 = ctr++ ^ rk[3]; s3 = ctr++ ^ rk[3];
const uint64_t in0 = *reinterpret_cast<const uint64_t *>(in); const uint64_t in0 = *reinterpret_cast<const uint64_t*>(in);
const uint64_t in1 = *reinterpret_cast<const uint64_t *>(in + 8); const uint64_t in1 = *reinterpret_cast<const uint64_t*>(in + 8);
in += 16; in += 16;
t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; 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]; 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]; 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) = 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 + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3);
out += 16; out += 16;
} while ((len -= 16) >= 16); } while ((len -= 16) >= 16);
} else { }
else {
do { do {
uint32_t s0, s1, s2, s3, t0, t1, t2, t3; uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
s0 = ctr0rk0; s0 = ctr0rk0;
@ -428,7 +430,7 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
in += 16; in += 16;
} while ((len -= 16) >= 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 // 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 --------------------------------------------------------------------------------- // 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, const uint32_t AES::Te0[256] = { 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
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, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
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, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
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, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a}; 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
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, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
0x15151515, 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
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, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
0xa8a8a8a8, 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
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, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
0x79797979, 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
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, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
0xdfdfdfdf, 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616}; 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a };
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, const uint32_t AES::Te4[256] = { 0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676,
0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0,
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, 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131, 0x15151515,
0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575,
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, 0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484,
0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf,
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, 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xa8a8a8a8,
0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742}; 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2,
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, 0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373,
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, 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb,
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, 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, 0x79797979,
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}; 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808,
const uint32_t AES::rcon[15] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000}; 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[0] = Utils::loadBigEndian<uint32_t>(key);
rk[1] = Utils::loadBigEndian< uint32_t >(key + 4); rk[1] = Utils::loadBigEndian<uint32_t>(key + 4);
rk[2] = Utils::loadBigEndian< uint32_t >(key + 8); rk[2] = Utils::loadBigEndian<uint32_t>(key + 8);
rk[3] = Utils::loadBigEndian< uint32_t >(key + 12); rk[3] = Utils::loadBigEndian<uint32_t>(key + 12);
rk[4] = Utils::loadBigEndian< uint32_t >(key + 16); rk[4] = Utils::loadBigEndian<uint32_t>(key + 16);
rk[5] = Utils::loadBigEndian< uint32_t >(key + 20); rk[5] = Utils::loadBigEndian<uint32_t>(key + 20);
rk[6] = Utils::loadBigEndian< uint32_t >(key + 24); rk[6] = Utils::loadBigEndian<uint32_t>(key + 24);
rk[7] = Utils::loadBigEndian< uint32_t >(key + 28); rk[7] = Utils::loadBigEndian<uint32_t>(key + 28);
for (int i = 0;;) { for (int i = 0;;) {
uint32_t temp = rk[7]; 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]; 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; 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[0] = Utils::ntoh(p_k.sw.h[0]);
p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]); 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 = 0x000000ff;
const uint32_t m8_8 = 0x0000ff00; const uint32_t m8_8 = 0x0000ff00;
const uint32_t m8_16 = 0x00ff0000; const uint32_t m8_16 = 0x00ff0000;
const uint32_t m8_24 = 0xff000000; const uint32_t m8_24 = 0xff000000;
uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0]; uint32_t s0 = Utils::loadBigEndian<uint32_t>(in) ^ rk[0];
uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1]; uint32_t s1 = Utils::loadBigEndian<uint32_t>(in + 4) ^ rk[1];
uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2]; uint32_t s2 = Utils::loadBigEndian<uint32_t>(in + 8) ^ rk[2];
uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3]; uint32_t s3 = Utils::loadBigEndian<uint32_t>(in + 12) ^ rk[3];
uint32_t t0, t1, t2, t3; 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]; 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]; 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]; 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, s0);
Utils::storeBigEndian< uint32_t >(out + 4, s1); Utils::storeBigEndian<uint32_t>(out + 4, s1);
Utils::storeBigEndian< uint32_t >(out + 8, s2); Utils::storeBigEndian<uint32_t>(out + 8, s2);
Utils::storeBigEndian< uint32_t >(out + 12, s3); 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; const uint32_t m8 = 0x000000ff;
uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0]; uint32_t s0 = Utils::loadBigEndian<uint32_t>(in) ^ rk[0];
uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1]; uint32_t s1 = Utils::loadBigEndian<uint32_t>(in + 4) ^ rk[1];
uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2]; uint32_t s2 = Utils::loadBigEndian<uint32_t>(in + 8) ^ rk[2];
uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3]; uint32_t s3 = Utils::loadBigEndian<uint32_t>(in + 12) ^ rk[3];
uint32_t t0, t1, t2, t3; 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]; 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]; 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]; 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]; 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]; 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]; 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]; 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]; 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, s0);
Utils::storeBigEndian< uint32_t >(out + 4, s1); Utils::storeBigEndian<uint32_t>(out + 4, s1);
Utils::storeBigEndian< uint32_t >(out + 8, s2); Utils::storeBigEndian<uint32_t>(out + 8, s2);
Utils::storeBigEndian< uint32_t >(out + 12, s3); Utils::storeBigEndian<uint32_t>(out + 12, s3);
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

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

View file

@ -11,8 +11,8 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "Constants.hpp"
#ifdef ZT_AES_AESNI #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__ #ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul"))) __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul")))
#endif #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); y = _mm_shuffle_epi8(y, s_sseSwapBytes);
__m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); __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 * 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 * fast it's highly unlikely to be a rate limiting factor except on massive
* servers and network infrastructure stuff. */ * 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 #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 kk13 = _mm512_broadcast_i32x4(k[13]);
const __m512i kk14 = _mm512_broadcast_i32x4(k[14]); const __m512i kk14 = _mm512_broadcast_i32x4(k[14]);
do { do {
__m512i p0 = _mm512_loadu_si512(reinterpret_cast<const __m512i *>(in)); __m512i p0 = _mm512_loadu_si512(reinterpret_cast<const __m512i*>(in));
__m512i d0 = _mm512_set_epi64( __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);
(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; c1 += 4;
in += 64; in += 64;
len -= 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, kk12);
d0 = _mm512_aesenc_epi128(d0, kk13); d0 = _mm512_aesenc_epi128(d0, kk13);
d0 = _mm512_aesenclast_epi128(d0, kk14); 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; out += 64;
} while (likely(len >= 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 kk13 = _mm256_broadcastsi128_si256(k[13]);
const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]); const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]);
do { do {
__m256i p0 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in)); __m256i p0 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(in));
__m256i p1 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in + 32)); __m256i p1 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(in + 32));
__m256i d0 = _mm256_set_epi64x( __m256i d0 = _mm256_set_epi64x((long long)Utils::hton(c1 + 1ULL), (long long)c0, (long long)Utils::hton(c1), (long long)c0);
(long long)Utils::hton(c1 + 1ULL), (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);
(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; c1 += 4;
in += 64; in += 64;
len -= 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); d1 = _mm256_aesenc_epi128(d1, kk13);
d0 = _mm256_aesenclast_epi128(d0, kk14); d0 = _mm256_aesenclast_epi128(d0, kk14);
d1 = _mm256_aesenclast_epi128(d1, 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), _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 + 32), _mm256_xor_si256(d1, p1));
out += 64; out += 64;
} while (likely(len >= 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__ #ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #endif
__m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept __m128i
p_init256_1_aesni(__m128i a, __m128i b) noexcept
{ {
__m128i x, y; __m128i x, y;
b = _mm_shuffle_epi32(b, 0xff); b = _mm_shuffle_epi32(b, 0xff);
@ -201,7 +195,8 @@ __m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #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; __m128i x, y, z;
y = _mm_aeskeygenassist_si128(a, 0x00); y = _mm_aeskeygenassist_si128(a, 0x00);
@ -216,25 +211,25 @@ __m128i p_init256_2_aesni(__m128i a, __m128i b) noexcept
return x; return x;
} }
} // anonymous namespace } // anonymous namespace
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul"))) __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul")))
#endif #endif
void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept 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. // Handle anything left over from a previous run that wasn't a multiple of 16 bytes.
if (_rp) { if (_rp) {
for (;;) { for (;;) {
if (!len) { if (! len) {
return; return;
} }
--len; --len;
_r[_rp++] = *(in++); _r[_rp++] = *(in++);
if (_rp == 16) { 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; 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 hh2 = _aes.p_k.ni.h2[1];
const __m128i hhh2 = _aes.p_k.ni.h2[2]; const __m128i hhh2 = _aes.p_k.ni.h2[2];
const __m128i hhhh2 = _aes.p_k.ni.h2[3]; 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; len &= 63U;
do { do {
__m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))), 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 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 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 d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 48)), sb);
in += 64; 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 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 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); a = _mm_xor_si128(_mm_slli_si128(c, 8), a);
b = _mm_xor_si128(_mm_srli_si128(c, 8), b); b = _mm_xor_si128(_mm_srli_si128(c, 8), b);
c = _mm_srli_epi32(a, 31); 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) { 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; in += 16;
len -= 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(). // Any overflow is cached for a later run or finish().
for (unsigned int i = 0; i < len; ++i) { for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[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__ #ifdef __GNUC__
@ -293,23 +292,23 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul,aes")))
#endif #endif
void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept 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. // Handle any remaining bytes, padding the last block with zeroes.
if (_rp) { if (_rp) {
while (_rp < 16) { while (_rp < 16) {
_r[_rp++] = 0; _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). // Interleave encryption of IV with the final GHASH of y XOR (length * 8).
// Then XOR these together to get the final tag. // 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]; 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_xor_si128(y, _mm_set_epi64x(0LL, (long long)Utils::hton((uint64_t)_len << 3U)));
y = _mm_shuffle_epi8(y, s_sseSwapBytes); 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 t1 = _mm_clmulepi64_si128(h, y, 0x00);
__m128i t2 = _mm_clmulepi64_si128(h, y, 0x01); __m128i t2 = _mm_clmulepi64_si128(h, y, 0x01);
__m128i t3 = _mm_clmulepi64_si128(h, y, 0x10); __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); t4 = _mm_xor_si128(t4, t3);
encIV = _mm_aesenclast_si128(encIV, k[14]); encIV = _mm_aesenclast_si128(encIV, k[14]);
t4 = _mm_xor_si128(t4, t5); 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__ #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]); const __m128i dd = _mm_set_epi64x(0, (long long)_ctr[0]);
uint64_t c1 = Utils::ntoh(_ctr[1]); 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 k0 = k[0];
const __m128i k1 = k[1]; const __m128i k1 = k[1];
const __m128i k2 = k[2]; 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; unsigned int totalLen = _len;
if ((totalLen & 15U)) { if ((totalLen & 15U)) {
for (;;) { for (;;) {
if (unlikely(!len)) { if (unlikely(! len)) {
_ctr[1] = Utils::hton(c1); _ctr[1] = Utils::hton(c1);
_len = totalLen; _len = totalLen;
return; return;
} }
--len; --len;
out[totalLen++] = *(in++); out[totalLen++] = *(in++);
if (!(totalLen & 15U)) { if (! (totalLen & 15U)) {
__m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1);
d0 = _mm_xor_si128(d0, k0); d0 = _mm_xor_si128(d0, k0);
d0 = _mm_aesenc_si128(d0, k1); 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, k8);
d0 = _mm_aesenc_si128(d0, k9); d0 = _mm_aesenc_si128(d0, k9);
d0 = _mm_aesenc_si128(d0, k10); 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); d0 = _mm_aesenc_si128(d0, k11);
const __m128i p0 = _mm_loadu_si128(outblk); const __m128i p0 = _mm_loadu_si128(outblk);
d0 = _mm_aesenc_si128(d0, k12); 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; _len = totalLen + len;
if (likely(len >= 64)) { if (likely(len >= 64)) {
#if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) #if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
if (Utils::CPUID.vaes && (len >= 256)) { if (Utils::CPUID.vaes && (len >= 256)) {
if (Utils::CPUID.avx512f) { if (Utils::CPUID.avx512f) {
p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k); p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k);
} else { }
else {
p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k);
} }
goto skip_conventional_aesni_64; goto skip_conventional_aesni_64;
} }
#endif #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)) { if (Utils::CPUID.vaes && (len >= 256)) {
p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k);
goto skip_conventional_aesni_64; goto skip_conventional_aesni_64;
} }
#endif #endif
const uint8_t *const eof64 = in + (len & ~((unsigned int)63)); const uint8_t* const eof64 = in + (len & ~((unsigned int)63));
len &= 63; len &= 63;
__m128i d0, d1, d2, d3; __m128i d0, d1, d2, d3;
do { 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); d1 = _mm_aesenc_si128(d1, k13);
d2 = _mm_aesenc_si128(d2, k13); d2 = _mm_aesenc_si128(d2, k13);
d3 = _mm_aesenc_si128(d3, k13); d3 = _mm_aesenc_si128(d3, k13);
d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))); 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))); 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))); 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))); d3 = _mm_xor_si128(_mm_aesenclast_si128(d3, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 48)));
in += 64; in += 64;
_mm_storeu_si128(reinterpret_cast<__m128i *>(out), d0); _mm_storeu_si128(reinterpret_cast<__m128i*>(out), d0);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 16), d1); _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 + 32), d2);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 48), d3); _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 48), d3);
out += 64; out += 64;
} while (likely(in != eof64)); } while (likely(in != eof64));
} }
skip_conventional_aesni_64: skip_conventional_aesni_64:
while (len >= 16) { while (len >= 16) {
__m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1);
d0 = _mm_xor_si128(d0, k0); 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, k11);
d0 = _mm_aesenc_si128(d0, k12); d0 = _mm_aesenc_si128(d0, k12);
d0 = _mm_aesenc_si128(d0, k13); 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; in += 16;
len -= 16; len -= 16;
out += 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 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; __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[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[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[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[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)); 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[26] = _mm_aesimc_si128(k2);
p_k.ni.k[27] = _mm_aesimc_si128(k1); 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, k1);
h = _mm_aesenc_si128(h, k2); h = _mm_aesenc_si128(h, k2);
h = _mm_aesenc_si128(h, k3); h = _mm_aesenc_si128(h, k3);
@ -631,7 +629,7 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #endif
void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept 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_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[1]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[2]); 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[11]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]); tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[13]); 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__ #ifdef __GNUC__
@ -654,7 +652,7 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #endif
void AES::p_decrypt_aesni(const void *in, void *out) const noexcept 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_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[15]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[16]); 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[25]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]); tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[27]); 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 "AES.hpp"
#include "Constants.hpp"
#ifdef ZT_AES_NEON #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); y = vrbitq_u8(y);
const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087)); const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087));
t0 = vextq_u8(y, y, 8); 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__("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__("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__("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__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(h), "w"(t0));
t0 = veorq_u8(t0, t1); t0 = veorq_u8(t0, t1);
t1 = vextq_u8(z, t0, 8); t1 = vextq_u8(z, t0, 8);
r0 = veorq_u8(r0, t1); r0 = veorq_u8(r0, t1);
t1 = vextq_u8(t0, z, 8); t1 = vextq_u8(t0, z, 8);
r1 = veorq_u8(r1, t1); 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); t1 = vextq_u8(t0, z, 8);
r1 = veorq_u8(r1, t1); r1 = veorq_u8(r1, t1);
t1 = vextq_u8(z, t0, 8); t1 = vextq_u8(z, t0, 8);
r0 = veorq_u8(r0, t1); 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)); 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; const uint8x16_t h = _aes.p_k.neon.h;
if (_rp) { if (_rp) {
for(;;) { for (;;) {
if (!len) { if (! len) {
return; return;
} }
--len; --len;
@ -74,18 +74,18 @@ void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept
len -= 16; 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) { for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[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 void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept
{ {
uint64_t tmp[2]; 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; const uint8x16_t h = _aes.p_k.neon.h;
if (_rp) { 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[0] = Utils::hton((uint64_t)_len << 3U);
tmp[1] = 0; 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 #if __BYTE_ORDER == __BIG_ENDIAN
reinterpret_cast<uint32_t *>(tmp)[3] = 0x00000001; reinterpret_cast<uint32_t*>(tmp)[3] = 0x00000001;
#else #else
reinterpret_cast<uint32_t *>(tmp)[3] = 0x01000000; reinterpret_cast<uint32_t*>(tmp)[3] = 0x01000000;
#endif #endif
_aes.encrypt(tmp, tmp); _aes.encrypt(tmp, tmp);
uint8x16_t yy = y; uint8x16_t yy = y;
Utils::storeMachineEndian< uint64_t >(tag, tmp[0] ^ reinterpret_cast<const uint64_t *>(&yy)[0]); 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 + 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))); uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast<uint8_t*>(_ctr)));
const uint32x4_t one = {0,0,0,1}; const uint32x4_t one = { 0, 0, 0, 1 };
uint8x16_t k0 = _aes.p_k.neon.ek[0]; uint8x16_t k0 = _aes.p_k.neon.ek[0];
uint8x16_t k1 = _aes.p_k.neon.ek[1]; 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; unsigned int totalLen = _len;
if ((totalLen & 15U) != 0) { if ((totalLen & 15U) != 0) {
for (;;) { for (;;) {
if (unlikely(!len)) { if (unlikely(! len)) {
vst1q_u8(reinterpret_cast<uint8_t *>(_ctr), vrev32q_u8(dd)); vst1q_u8(reinterpret_cast<uint8_t*>(_ctr), vrev32q_u8(dd));
_len = totalLen; _len = totalLen;
return; return;
} }
--len; --len;
out[totalLen++] = *(in++); out[totalLen++] = *(in++);
if ((totalLen & 15U) == 0) { 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 d0 = vrev32q_u8(dd);
uint8x16_t pt = vld1q_u8(otmp); uint8x16_t pt = vld1q_u8(otmp);
d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); 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]; 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_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_ROTWORD(w) (((w) << 8U) | ((w) >> 24U))
#define ZT_INIT_ARMNEON_CRYPTO_NK 8 #define ZT_INIT_ARMNEON_CRYPTO_NK 8
#define ZT_INIT_ARMNEON_CRYPTO_NB 4 #define ZT_INIT_ARMNEON_CRYPTO_NB 4
#define ZT_INIT_ARMNEON_CRYPTO_NR 14 #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, 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,
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, 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,
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}; 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]; 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; 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]; 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]; uint32_t t = w[i - 1];
const unsigned int imod = i & (ZT_INIT_ARMNEON_CRYPTO_NK - 1); const unsigned int imod = i & (ZT_INIT_ARMNEON_CRYPTO_NK - 1);
if (imod == 0) { if (imod == 0) {
t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(ZT_INIT_ARMNEON_CRYPTO_ROTWORD(t)) ^ rcon[(i - 1) / ZT_INIT_ARMNEON_CRYPTO_NK]; 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); t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(t);
} }
w[i] = w[i - ZT_INIT_ARMNEON_CRYPTO_NK] ^ 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]); w[i] = Utils::hton(w[i]);
} }
p_k.neon.dk[0] = p_k.neon.ek[14]; 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[i] = vaesimcq_u8(p_k.neon.ek[14 - i]);
} }
p_k.neon.dk[14] = p_k.neon.ek[0]; 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]); 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[0]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1])); tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[2])); 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[11]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[12])); 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]); 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[0]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1])); tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[2])); 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[11]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[12])); 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]); 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 #ifndef ZT_ADDRESS_HPP
#define ZT_ADDRESS_HPP #define ZT_ADDRESS_HPP
#include <stdio.h> #include "Buffer.hpp"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <string>
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "Buffer.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
namespace ZeroTier { namespace ZeroTier {
/** /**
* A ZeroTier address * A ZeroTier address
*/ */
class Address class Address {
{ public:
public: Address() : _a(0)
Address() : _a(0) {} {
Address(const Address &a) : _a(a._a) {} }
Address(uint64_t a) : _a(a & 0xffffffffffULL) {} 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 bits Raw address -- 5 bytes, big-endian byte order
* @param len Length of array * @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 Address& a)
inline Address &operator=(const uint64_t a) { _a = (a & 0xffffffffffULL); return *this; } {
_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 bits Raw address -- 5 bytes, big-endian byte order
* @param len Length of array * @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) { if (len < ZT_ADDRESS_LENGTH) {
_a = 0; _a = 0;
return; return;
} }
const unsigned char *b = (const unsigned char *)bits; const unsigned char* b = (const unsigned char*)bits;
uint64_t a = ((uint64_t)*b++) << 32; uint64_t a = ((uint64_t)*b++) << 32;
a |= ((uint64_t)*b++) << 24; a |= ((uint64_t)*b++) << 24;
a |= ((uint64_t)*b++) << 16; a |= ((uint64_t)*b++) << 16;
@ -69,12 +84,12 @@ public:
* @param bits Buffer to hold 5-byte address in big-endian byte order * @param bits Buffer to hold 5-byte address in big-endian byte order
* @param len Length of array * @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) { if (len < ZT_ADDRESS_LENGTH) {
return; return;
} }
unsigned char *b = (unsigned char *)bits; unsigned char* b = (unsigned char*)bits;
*(b++) = (unsigned char)((_a >> 32) & 0xff); *(b++) = (unsigned char)((_a >> 32) & 0xff);
*(b++) = (unsigned char)((_a >> 24) & 0xff); *(b++) = (unsigned char)((_a >> 24) & 0xff);
*(b++) = (unsigned char)((_a >> 16) & 0xff); *(b++) = (unsigned char)((_a >> 16) & 0xff);
@ -87,10 +102,9 @@ public:
* *
* @param b Buffer to append to * @param b Buffer to append to
*/ */
template<unsigned int C> template <unsigned int C> inline void appendTo(Buffer<C>& b) const
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 >> 32) & 0xff);
*(p++) = (unsigned char)((_a >> 24) & 0xff); *(p++) = (unsigned char)((_a >> 24) & 0xff);
*(p++) = (unsigned char)((_a >> 16) & 0xff); *(p++) = (unsigned char)((_a >> 16) & 0xff);
@ -101,22 +115,34 @@ public:
/** /**
* @return Integer containing address (0 to 2^40) * @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 * @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 * @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 * @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 * Check if this address is reserved
@ -127,34 +153,79 @@ public:
* *
* @return True if address is reserved and may not be used * @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) * @param i Value from 0 to 4 (inclusive)
* @return Byte at said position (address interpreted in big-endian order) * @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
inline bool operator!=(const uint64_t &a) const { return (_a != (a & 0xffffffffffULL)); } {
inline bool operator>(const uint64_t &a) const { return (_a > (a & 0xffffffffffULL)); } 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
inline bool operator<=(const uint64_t &a) const { return (_a <= (a & 0xffffffffffULL)); } {
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
inline bool operator!=(const Address &a) const { return (_a != a._a); } {
inline bool operator>(const Address &a) const { return (_a > a._a); } 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
inline bool operator<=(const Address &a) const { return (_a <= a._a); } {
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; uint64_t _a;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -25,15 +25,17 @@ namespace ZeroTier {
/** /**
* Simple atomic counter supporting increment and decrement * Simple atomic counter supporting increment and decrement
*/ */
class AtomicCounter class AtomicCounter {
{ public:
public: AtomicCounter()
AtomicCounter() { _v = 0; } {
_v = 0;
}
inline int load() const inline int load() const
{ {
#ifdef __GNUC__ #ifdef __GNUC__
return __sync_or_and_fetch(const_cast<int *>(&_v),0); return __sync_or_and_fetch(const_cast<int*>(&_v), 0);
#else #else
return _v.load(); return _v.load();
#endif #endif
@ -42,7 +44,7 @@ public:
inline int operator++() inline int operator++()
{ {
#ifdef __GNUC__ #ifdef __GNUC__
return __sync_add_and_fetch(&_v,1); return __sync_add_and_fetch(&_v, 1);
#else #else
return ++_v; return ++_v;
#endif #endif
@ -51,15 +53,20 @@ public:
inline int operator--() inline int operator--()
{ {
#ifdef __GNUC__ #ifdef __GNUC__
return __sync_sub_and_fetch(&_v,1); return __sync_sub_and_fetch(&_v, 1);
#else #else
return --_v; return --_v;
#endif #endif
} }
private: private:
AtomicCounter(const AtomicCounter &) {} AtomicCounter(const AtomicCounter&)
const AtomicCounter &operator=(const AtomicCounter &) { return *this; } {
}
const AtomicCounter& operator=(const AtomicCounter&)
{
return *this;
}
#ifdef __GNUC__ #ifdef __GNUC__
int _v; int _v;
@ -68,6 +75,6 @@ private:
#endif #endif
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #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 (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) {
if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS && _paths[_abPathIdx].p) { 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; 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); log("found non-preferred primary link (_abPathIdx=%d)", _abPathIdx);
_abPathIdx = nonPreferredPathIdx; _abPathIdx = nonPreferredPathIdx;
} }

View file

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

View file

@ -14,18 +14,17 @@
#ifndef ZT_BUFFER_HPP #ifndef ZT_BUFFER_HPP
#define 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 "Constants.hpp"
#include "Utils.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__)) #define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__))
#else #else
#define ZT_VAR_MAY_ALIAS #define ZT_VAR_MAY_ALIAS
@ -46,36 +45,57 @@ namespace ZeroTier {
* *
* @tparam C Total capacity * @tparam C Total capacity
*/ */
template<unsigned int C> template <unsigned int C> class Buffer {
class Buffer
{
// I love me! // I love me!
template <unsigned int C2> friend class Buffer; template <unsigned int C2> friend class Buffer;
public: public:
// STL container idioms // STL container idioms
typedef unsigned char value_type; typedef unsigned char value_type;
typedef unsigned char * pointer; typedef unsigned char* pointer;
typedef const char * const_pointer; typedef const char* const_pointer;
typedef char & reference; typedef char& reference;
typedef const char & const_reference; typedef const char& const_reference;
typedef char * iterator; typedef char* iterator;
typedef const char * const_iterator; typedef const char* const_iterator;
typedef unsigned int size_type; typedef unsigned int size_type;
typedef int difference_type; typedef int difference_type;
typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
inline iterator begin() { return _b; } inline iterator begin()
inline iterator end() { return (_b + _l); } {
inline const_iterator begin() const { return _b; } return _b;
inline const_iterator end() const { return (_b + _l); } }
inline reverse_iterator rbegin() { return reverse_iterator(begin()); } inline iterator end()
inline reverse_iterator rend() { return reverse_iterator(end()); } {
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); } return (_b + _l);
inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); } }
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() : Buffer() : _l(0)
_l(0)
{ {
} }
@ -87,37 +107,36 @@ public:
_l = l; _l = l;
} }
template<unsigned int C2> template <unsigned int C2> Buffer(const Buffer<C2>& b)
Buffer(const Buffer<C2> &b)
{ {
*this = 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> template <unsigned int C2> inline Buffer& operator=(const Buffer<C2>& b)
inline Buffer &operator=(const Buffer<C2> &b)
{ {
if (unlikely(b._l > C)) { if (unlikely(b._l > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
if (C2 == C) { if (C2 == C) {
memcpy(this,&b,sizeof(Buffer<C>)); memcpy(this, &b, sizeof(Buffer<C>));
} else { }
memcpy(_b,b._b,_l = b._l); else {
memcpy(_b, b._b, _l = b._l);
} }
return *this; return *this;
} }
inline void copyFrom(const void *b,unsigned int l) inline void copyFrom(const void* b, unsigned int l)
{ {
if (unlikely(l > C)) { if (unlikely(l > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
memcpy(_b,b,l); memcpy(_b, b, l);
_l = l; _l = l;
} }
@ -129,12 +148,12 @@ public:
return (unsigned char)_b[i]; return (unsigned char)_b[i];
} }
unsigned char &operator[](const unsigned int i) unsigned char& operator[](const unsigned int i)
{ {
if (unlikely(i >= _l)) { if (unlikely(i >= _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; 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 * @return Pointer to field data
* @throws std::out_of_range Field extends beyond data size * @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)) { if (unlikely((i + l) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; 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)) { if (unlikely((i + l) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; 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 * @param v Value
* @tparam T Integer type (e.g. uint16_t, int64_t) * @tparam T Integer type (e.g. uint16_t, int64_t)
*/ */
template<typename T> template <typename T> inline void setAt(unsigned int i, const T v)
inline void setAt(unsigned int i,const T v)
{ {
if (unlikely((i + sizeof(T)) > _l)) { if (unlikely((i + sizeof(T)) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_TYPE_PUNNING
uint8_t *p = reinterpret_cast<uint8_t *>(_b + i); uint8_t* p = reinterpret_cast<uint8_t*>(_b + i);
for(unsigned int x=1;x<=sizeof(T);++x) { for (unsigned int x = 1; x <= sizeof(T); ++x) {
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
} }
#else #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); *p = Utils::hton(v);
#endif #endif
} }
@ -196,22 +214,21 @@ public:
* @tparam T Integer type (e.g. uint16_t, int64_t) * @tparam T Integer type (e.g. uint16_t, int64_t)
* @return Integer value * @return Integer value
*/ */
template<typename T> template <typename T> inline T at(unsigned int i) const
inline T at(unsigned int i) const
{ {
if (unlikely((i + sizeof(T)) > _l)) { if (unlikely((i + sizeof(T)) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_TYPE_PUNNING
T v = 0; T v = 0;
const uint8_t *p = reinterpret_cast<const uint8_t *>(_b + i); const uint8_t* p = reinterpret_cast<const uint8_t*>(_b + i);
for(unsigned int x=0;x<sizeof(T);++x) { for (unsigned int x = 0; x < sizeof(T); ++x) {
v <<= 8; v <<= 8;
v |= (T)*(p++); v |= (T) * (p++);
} }
return v; return v;
#else #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); return Utils::ntoh(*p);
#endif #endif
} }
@ -223,19 +240,18 @@ public:
* @tparam T Integer type (e.g. uint16_t, int64_t) * @tparam T Integer type (e.g. uint16_t, int64_t)
* @throws std::out_of_range Attempt to append beyond capacity * @throws std::out_of_range Attempt to append beyond capacity
*/ */
template<typename T> template <typename T> inline void append(const T v)
inline void append(const T v)
{ {
if (unlikely((_l + sizeof(T)) > C)) { if (unlikely((_l + sizeof(T)) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_TYPE_PUNNING
uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l); uint8_t* p = reinterpret_cast<uint8_t*>(_b + _l);
for(unsigned int x=1;x<=sizeof(T);++x) { for (unsigned int x = 1; x <= sizeof(T); ++x) {
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
} }
#else #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); *p = Utils::hton(v);
#endif #endif
_l += sizeof(T); _l += sizeof(T);
@ -248,12 +264,12 @@ public:
* @param n Number of times to append * @param n Number of times to append
* @throws std::out_of_range Attempt to append beyond capacity * @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)) { if (unlikely((_l + n) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; 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; _b[_l++] = (char)c;
} }
} }
@ -268,7 +284,7 @@ public:
if (unlikely((_l + n) > C)) { if (unlikely((_l + n) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
Utils::getSecureRandom(_b + _l,n); Utils::getSecureRandom(_b + _l, n);
_l += n; _l += n;
} }
@ -279,12 +295,12 @@ public:
* @param l Length * @param l Length
* @throws std::out_of_range Attempt to append beyond capacity * @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)) { if (unlikely((_l + l) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
memcpy(_b + _l,b,l); memcpy(_b + _l, b, l);
_l += l; _l += l;
} }
@ -294,13 +310,13 @@ public:
* @param s C string * @param s C string
* @throws std::out_of_range Attempt to append beyond capacity * @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)) { if (unlikely(_l >= C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
if (!(_b[_l++] = *(s++))) { if (! (_b[_l++] = *(s++))) {
break; break;
} }
} }
@ -313,10 +329,9 @@ public:
* @tparam C2 Capacity of second buffer (typically inferred) * @tparam C2 Capacity of second buffer (typically inferred)
* @throws std::out_of_range Attempt to append beyond capacity * @throws std::out_of_range Attempt to append beyond capacity
*/ */
template<unsigned int C2> template <unsigned int C2> inline void append(const Buffer<C2>& b)
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 * @param l Length of field to append
* @return Pointer to beginning of appended field of length 'l' * @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)) { if (unlikely((_l + l) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
char *r = _b + _l; char* r = _b + _l;
_l += l; _l += l;
return r; return r;
} }
@ -379,13 +394,13 @@ public:
*/ */
inline void behead(const unsigned int at) inline void behead(const unsigned int at)
{ {
if (!at) { if (! at) {
return; return;
} }
if (unlikely(at > _l)) { if (unlikely(at > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; 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 * @param length Length of block to erase
* @throws std::out_of_range Position plus length is beyond size of buffer * @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; const unsigned int endr = at + length;
if (unlikely(endr > _l)) { if (unlikely(endr > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
::memmove(_b + at,_b + endr,_l - endr); ::memmove(_b + at, _b + endr, _l - endr);
_l -= length; _l -= length;
} }
/** /**
* Set buffer data length to zero * Set buffer data length to zero
*/ */
inline void clear() { _l = 0; } inline void clear()
{
_l = 0;
}
/** /**
* Zero buffer up to size() * Zero buffer up to size()
*/ */
inline void zero() { memset(_b,0,_l); } inline void zero()
{
memset(_b, 0, _l);
}
/** /**
* Zero unused capacity area * 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 * 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 * @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 * @return Non-constant pointer to data in buffer
*/ */
inline void *unsafeData() { return _b; } inline void* unsafeData()
{
return _b;
}
/** /**
* @return Size of data in buffer * @return Size of data in buffer
*/ */
inline unsigned int size() const { return _l; } inline unsigned int size() const
{
return _l;
}
/** /**
* @return Capacity of buffer * @return Capacity of buffer
*/ */
inline unsigned int capacity() const { return C; } inline unsigned int capacity() const
{
return C;
}
template<unsigned int C2> template <unsigned int C2> inline bool operator==(const Buffer<C2>& b) const
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> template <unsigned int C2> inline bool operator!=(const Buffer<C2>& b) const
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> template <unsigned int C2> inline bool operator<(const Buffer<C2>& b) const
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> template <unsigned int C2> inline bool operator>(const Buffer<C2>& b) const
inline bool operator>(const Buffer<C2> &b) const
{ {
return (b < *this); return (b < *this);
} }
template<unsigned int C2> template <unsigned int C2> inline bool operator<=(const Buffer<C2>& b) const
inline bool operator<=(const Buffer<C2> &b) const
{ {
return !(b < *this); return ! (b < *this);
} }
template<unsigned int C2> template <unsigned int C2> inline bool operator>=(const Buffer<C2>& b) const
inline bool operator>=(const Buffer<C2> &b) const
{ {
return !(*this < b); return ! (*this < b);
} }
private: private:
char ZT_VAR_MAY_ALIAS _b[C]; char ZT_VAR_MAY_ALIAS _b[C];
unsigned int _l; unsigned int _l;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

@ -12,15 +12,16 @@
/****/ /****/
#include "CertificateOfMembership.hpp" #include "CertificateOfMembership.hpp"
#include "RuntimeEnvironment.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier { 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].id = COM_RESERVED_ID_TIMESTAMP;
_qualifiers[0].value = 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. // using the original COM format. Format may be revised in the future to make this cleaner.
uint64_t idHash[6]; uint64_t idHash[6];
issuedTo.publicKeyHash(idHash); 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].id = (uint64_t)(i + 3);
_qualifiers[i + 3].value = Utils::ntoh(idHash[i]); _qualifiers[i + 3].value = Utils::ntoh(idHash[i]);
_qualifiers[i + 3].maxDelta = 0xffffffffffffffffULL; _qualifiers[i + 3].maxDelta = 0xffffffffffffffffULL;
} }
_qualifierCount = 7; _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; return false;
} }
std::map< uint64_t, uint64_t > otherFields; std::map<uint64_t, uint64_t> otherFields;
for(unsigned int i=0;i<other._qualifierCount;++i) { for (unsigned int i = 0; i < other._qualifierCount; ++i) {
otherFields[other._qualifiers[i].id] = other._qualifiers[i].value; otherFields[other._qualifiers[i].id] = other._qualifiers[i].value;
} }
bool fullIdentityVerification = false; 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; const uint64_t qid = _qualifiers[i].id;
if ((qid >= 3)&&(qid <= 6)) { if ((qid >= 3) && (qid <= 6)) {
fullIdentityVerification = true; 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()) { if (otherQ == otherFields.end()) {
return false; return false;
} }
@ -79,8 +80,8 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, c
if (fullIdentityVerification) { if (fullIdentityVerification) {
uint64_t idHash[6]; uint64_t idHash[6];
otherIdentity.publicKeyHash(idHash); otherIdentity.publicKeyHash(idHash);
for(unsigned long i=0;i<4;++i) { for (unsigned long i = 0; i < 4; ++i) {
std::map< uint64_t, uint64_t >::iterator otherQ(otherFields.find((uint64_t)(i + 3))); std::map<uint64_t, uint64_t>::iterator otherQ(otherFields.find((uint64_t)(i + 3)));
if (otherQ == otherFields.end()) { if (otherQ == otherFields.end()) {
return false; return false;
} }
@ -93,46 +94,47 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, c
return true; return true;
} }
bool CertificateOfMembership::sign(const Identity &with) bool CertificateOfMembership::sign(const Identity& with)
{ {
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
unsigned int ptr = 0; 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].id);
buf[ptr++] = Utils::hton(_qualifiers[i].value); buf[ptr++] = Utils::hton(_qualifiers[i].value);
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
} }
try { try {
_signature = with.sign(buf,ptr * sizeof(uint64_t)); _signature = with.sign(buf, ptr * sizeof(uint64_t));
_signedBy = with.address(); _signedBy = with.address();
return true; return true;
} catch ( ... ) { }
catch (...) {
_signedBy.zero(); _signedBy.zero();
return false; 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; return -1;
} }
const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (!id) { if (! id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1; return 1;
} }
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
unsigned int ptr = 0; 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].id);
buf[ptr++] = Utils::hton(_qualifiers[i].value); buf[ptr++] = Utils::hton(_qualifiers[i].value);
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); 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 #ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP
#define ZT_CERTIFICATEOFMEMBERSHIP_HPP #define ZT_CERTIFICATEOFMEMBERSHIP_HPP
#include <stdint.h> #include "Address.hpp"
#include <string.h> #include "Buffer.hpp"
#include "C25519.hpp"
#include <string>
#include <stdexcept>
#include <algorithm>
#include "Constants.hpp" #include "Constants.hpp"
#include "Credential.hpp" #include "Credential.hpp"
#include "Buffer.hpp"
#include "Address.hpp"
#include "C25519.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Utils.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) * 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 * This is a memcpy()'able structure and is safe (in a crash sense) to modify
* without locks. * without locks.
*/ */
class CertificateOfMembership : public Credential class CertificateOfMembership : public Credential {
{ public:
public: static inline Credential::Type credentialType()
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COM; } {
return Credential::CREDENTIAL_TYPE_COM;
}
/** /**
* Reserved qualifier IDs * Reserved qualifier IDs
@ -78,8 +79,7 @@ public:
* Addition of new required fields requires that code in hasRequiredFields * Addition of new required fields requires that code in hasRequiredFields
* be updated as well. * be updated as well.
*/ */
enum ReservedId enum ReservedId {
{
/** /**
* Timestamp of certificate * Timestamp of certificate
*/ */
@ -101,8 +101,9 @@ public:
/** /**
* Create an empty certificate of membership * Create an empty certificate of membership
*/ */
CertificateOfMembership() : CertificateOfMembership() : _qualifierCount(0)
_qualifierCount(0) {} {
}
/** /**
* Create from required fields common to all networks * Create from required fields common to all networks
@ -112,7 +113,7 @@ public:
* @param nwid Network ID * @param nwid Network ID
* @param issuedTo Certificate recipient * @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 * Create from binary-serialized COM in buffer
@ -120,28 +121,33 @@ public:
* @param b Buffer to deserialize from * @param b Buffer to deserialize from
* @param startAt Position to start in buffer * @param startAt Position to start in buffer
*/ */
template<unsigned int C> template <unsigned int C> CertificateOfMembership(const Buffer<C>& b, unsigned int startAt = 0)
CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0)
{ {
deserialize(b,startAt); deserialize(b, startAt);
} }
/** /**
* @return True if there's something here * @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 * @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 * @return Timestamp for this cert and maximum delta for timestamp
*/ */
inline int64_t timestamp() const 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) { if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) {
return _qualifiers[i].value; return _qualifiers[i].value;
} }
@ -154,7 +160,7 @@ public:
*/ */
inline Address issuedTo() const 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) { if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) {
return Address(_qualifiers[i].value); return Address(_qualifiers[i].value);
} }
@ -167,7 +173,7 @@ public:
*/ */
inline uint64_t networkId() const 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) { if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) {
return _qualifiers[i].value; return _qualifiers[i].value;
} }
@ -189,7 +195,7 @@ public:
* @param otherIdentity Identity of other node * @param otherIdentity Identity of other node
* @return True if certs agree and 'other' may be communicated with * @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 * Sign this certificate
@ -197,7 +203,7 @@ public:
* @param with Identity to sign with, must include private key * @param with Identity to sign with, must include private key
* @return True if signature was successful * @return True if signature was successful
*/ */
bool sign(const Identity &with); bool sign(const Identity& with);
/** /**
* Verify this COM and its signature * 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 * @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 * @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 * @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 * @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> template <unsigned int C> inline void serialize(Buffer<C>& b) const
inline void serialize(Buffer<C> &b) const
{ {
b.append((uint8_t)1); b.append((uint8_t)1);
b.append((uint16_t)_qualifierCount); 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].id);
b.append(_qualifiers[i].value); b.append(_qualifiers[i].value);
b.append(_qualifiers[i].maxDelta); b.append(_qualifiers[i].maxDelta);
} }
_signedBy.appendTo(b); _signedBy.appendTo(b);
if (_signedBy) { if (_signedBy) {
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); b.append(_signature.data, ZT_C25519_SIGNATURE_LEN);
} }
} }
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{ {
unsigned int p = startAt; unsigned int p = startAt;
@ -249,11 +259,12 @@ public:
unsigned int numq = b.template at<uint16_t>(p); unsigned int numq = b.template at<uint16_t>(p);
p += sizeof(uint16_t); p += sizeof(uint16_t);
uint64_t lastId = 0; 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); const uint64_t qid = b.template at<uint64_t>(p);
if (qid < lastId) { if (qid < lastId) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING;
} else { }
else {
lastId = qid; lastId = qid;
} }
if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
@ -262,23 +273,24 @@ public:
_qualifiers[_qualifierCount].maxDelta = b.template at<uint64_t>(p + 16); _qualifiers[_qualifierCount].maxDelta = b.template at<uint64_t>(p + 16);
p += 24; p += 24;
++_qualifierCount; ++_qualifierCount;
} else { }
else {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; 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; p += ZT_ADDRESS_LENGTH;
if (_signedBy) { 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; p += ZT_C25519_SIGNATURE_LEN;
} }
return (p - startAt); return (p - startAt);
} }
inline bool operator==(const CertificateOfMembership &c) const inline bool operator==(const CertificateOfMembership& c) const
{ {
if (_signedBy != c._signedBy) { if (_signedBy != c._signedBy) {
return false; return false;
@ -286,25 +298,32 @@ public:
if (_qualifierCount != c._qualifierCount) { if (_qualifierCount != c._qualifierCount) {
return false; return false;
} }
for(unsigned int i=0;i<_qualifierCount;++i) { for (unsigned int i = 0; i < _qualifierCount; ++i) {
const _Qualifier &a = _qualifiers[i]; const _Qualifier& a = _qualifiers[i];
const _Qualifier &b = c._qualifiers[i]; const _Qualifier& b = c._qualifiers[i];
if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta)) { if ((a.id != b.id) || (a.value != b.value) || (a.maxDelta != b.maxDelta)) {
return false; 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)); } inline bool operator!=(const CertificateOfMembership& c) const
private:
struct _Qualifier
{ {
_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 id;
uint64_t value; uint64_t value;
uint64_t maxDelta; 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; Address _signedBy;
@ -313,6 +332,6 @@ private:
C25519::Signature _signature; C25519::Signature _signature;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

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

View file

@ -14,20 +14,20 @@
#ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP #ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP
#define 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 <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.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 // Max things per CertificateOfOwnership
#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS 16 #define ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS 16
@ -41,84 +41,102 @@ class RuntimeEnvironment;
/** /**
* Certificate indicating ownership of a network identifier * Certificate indicating ownership of a network identifier
*/ */
class CertificateOfOwnership : public Credential class CertificateOfOwnership : public Credential {
{ public:
public: static inline Credential::Type credentialType()
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COO; }
enum Thing
{ {
THING_NULL = 0, return Credential::CREDENTIAL_TYPE_COO;
THING_MAC_ADDRESS = 1, }
THING_IPV4_ADDRESS = 2,
THING_IPV6_ADDRESS = 3 enum Thing { THING_NULL = 0, THING_MAC_ADDRESS = 1, THING_IPV4_ADDRESS = 2, THING_IPV6_ADDRESS = 3 };
};
CertificateOfOwnership() 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; _networkId = nwid;
_ts = ts; _ts = ts;
_id = id; _id = id;
_issuedTo = issuedTo; _issuedTo = issuedTo;
} }
inline uint64_t networkId() const { return _networkId; } inline uint64_t networkId() const
inline int64_t timestamp() const { return _ts; } {
inline uint32_t id() const { return _id; } return _networkId;
inline unsigned int thingCount() const { return (unsigned int)_thingCount; } }
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 Thing thingType(const unsigned int i) const
inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; } {
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) { 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) { 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; return false;
} }
inline bool owns(const MAC &mac) const inline bool owns(const MAC& mac) const
{ {
uint8_t tmp[6]; uint8_t tmp[6];
mac.copyTo(tmp,6); mac.copyTo(tmp, 6);
return this->_owns(THING_MAC_ADDRESS,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) { if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
return; return;
} }
if (ip.ss_family == AF_INET) { if (ip.ss_family == AF_INET) {
_thingTypes[_thingCount] = THING_IPV4_ADDRESS; _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; ++_thingCount;
} else if (ip.ss_family == AF_INET6) { }
else if (ip.ss_family == AF_INET6) {
_thingTypes[_thingCount] = THING_IPV6_ADDRESS; _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; ++_thingCount;
} }
} }
inline void addThing(const MAC &mac) inline void addThing(const MAC& mac)
{ {
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) { if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
return; return;
} }
_thingTypes[_thingCount] = THING_MAC_ADDRESS; _thingTypes[_thingCount] = THING_MAC_ADDRESS;
mac.copyTo(_thingValues[_thingCount],6); mac.copyTo(_thingValues[_thingCount], 6);
++_thingCount; ++_thingCount;
} }
@ -126,13 +144,13 @@ public:
* @param signer Signing identity, must have private key * @param signer Signing identity, must have private key
* @return True if signature was successful * @return True if signature was successful
*/ */
inline bool sign(const Identity &signer) inline bool sign(const Identity& signer)
{ {
if (signer.hasPrivate()) { if (signer.hasPrivate()) {
Buffer<sizeof(CertificateOfOwnership) + 64> tmp; Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
_signedBy = signer.address(); _signedBy = signer.address();
this->serialize(tmp,true); this->serialize(tmp, true);
_signature = signer.sign(tmp.data(),tmp.size()); _signature = signer.sign(tmp.data(), tmp.size());
return true; return true;
} }
return false; 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 * @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 * @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> template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{ {
if (forSign) { if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -157,28 +174,27 @@ public:
b.append(_flags); b.append(_flags);
b.append(_id); b.append(_id);
b.append((uint16_t)_thingCount); 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((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); _issuedTo.appendTo(b);
_signedBy.appendTo(b); _signedBy.appendTo(b);
if (!forSign) { if (! forSign) {
b.append((uint8_t)1); // 1 == Ed25519 b.append((uint8_t)1); // 1 == Ed25519
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); 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) { if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
} }
} }
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{ {
unsigned int p = startAt; unsigned int p = startAt;
@ -194,26 +210,27 @@ public:
p += 4; p += 4;
_thingCount = b.template at<uint16_t>(p); _thingCount = b.template at<uint16_t>(p);
p += 2; 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) { if (i < ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
_thingTypes[i] = (uint8_t)b[p++]; _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; 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; 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; p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) { if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN) { if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
} }
p += 2; 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; p += ZT_C25519_SIGNATURE_LEN;
} else { }
else {
p += 2 + b.template at<uint16_t>(p); p += 2 + b.template at<uint16_t>(p);
} }
@ -226,13 +243,22 @@ public:
} }
// Provides natural sort order by ID // 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
inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); } {
return (memcmp(this, &coo, sizeof(CertificateOfOwnership)) == 0);
}
inline bool operator!=(const CertificateOfOwnership& coo) const
{
return (memcmp(this, &coo, sizeof(CertificateOfOwnership)) != 0);
}
private: private:
bool _owns(const Thing &t,const void *v,unsigned int l) const; bool _owns(const Thing& t, const void* v, unsigned int l) const;
uint64_t _networkId; uint64_t _networkId;
int64_t _ts; int64_t _ts;
@ -246,6 +272,6 @@ private:
C25519::Signature _signature; C25519::Signature _signature;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

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

View file

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

View file

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

View file

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

View file

@ -11,94 +11,98 @@
*/ */
/****/ /****/
#include <stdio.h> #include "Identity.hpp"
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "Constants.hpp" #include "Constants.hpp"
#include "Identity.hpp"
#include "SHA512.hpp" #include "SHA512.hpp"
#include "Salsa20.hpp" #include "Salsa20.hpp"
#include "Utils.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 // These can't be changed without a new identity type. They define the
// parameters of the hashcash hashing/searching algorithm. // parameters of the hashcash hashing/searching algorithm.
#define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 17 #define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 17
#define ZT_IDENTITY_GEN_MEMORY 2097152 #define ZT_IDENTITY_GEN_MEMORY 2097152
namespace ZeroTier { namespace ZeroTier {
// A memory-hard composition of SHA-512 and Salsa20 for hashcash hashing // 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 // Digest publicKey[] to obtain initial digest
SHA512(digest,publicKey,publicKeyBytes); SHA512(digest, publicKey, publicKeyBytes);
// Initialize genmem[] using Salsa20 in a CBC-like configuration since // Initialize genmem[] using Salsa20 in a CBC-like configuration since
// ordinary Salsa20 is randomly seek-able. This is good for a cipher // ordinary Salsa20 is randomly seek-able. This is good for a cipher
// but is not what we want for sequential memory-hardness. // but is not what we want for sequential memory-hardness.
memset(genmem,0,ZT_IDENTITY_GEN_MEMORY); memset(genmem, 0, ZT_IDENTITY_GEN_MEMORY);
Salsa20 s20(digest,(char *)digest + 32); Salsa20 s20(digest, (char*)digest + 32);
s20.crypt20((char *)genmem,(char *)genmem,64); s20.crypt20((char*)genmem, (char*)genmem, 64);
for(unsigned long i=64;i<ZT_IDENTITY_GEN_MEMORY;i+=64) { for (unsigned long i = 64; i < ZT_IDENTITY_GEN_MEMORY; i += 64) {
unsigned long k = i - 64; unsigned long k = i - 64;
*((uint64_t *)((char *)genmem + i)) = *((uint64_t *)((char *)genmem + k)); *((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 + 8)) = *((uint64_t*)((char*)genmem + k + 8));
*((uint64_t *)((char *)genmem + i + 16)) = *((uint64_t *)((char *)genmem + k + 16)); *((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 + 24)) = *((uint64_t*)((char*)genmem + k + 24));
*((uint64_t *)((char *)genmem + i + 32)) = *((uint64_t *)((char *)genmem + k + 32)); *((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 + 40)) = *((uint64_t*)((char*)genmem + k + 40));
*((uint64_t *)((char *)genmem + i + 48)) = *((uint64_t *)((char *)genmem + k + 48)); *((uint64_t*)((char*)genmem + i + 48)) = *((uint64_t*)((char*)genmem + k + 48));
*((uint64_t *)((char *)genmem + i + 56)) = *((uint64_t *)((char *)genmem + k + 56)); *((uint64_t*)((char*)genmem + i + 56)) = *((uint64_t*)((char*)genmem + k + 56));
s20.crypt20((char *)genmem + i,(char *)genmem + i,64); s20.crypt20((char*)genmem + i, (char*)genmem + i, 64);
} }
// Render final digest using genmem as a lookup table // Render final digest using genmem as a lookup table
for(unsigned long i=0;i<(ZT_IDENTITY_GEN_MEMORY / sizeof(uint64_t));) { 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 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))); 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 tmp = ((uint64_t*)genmem)[idx2];
((uint64_t *)genmem)[idx2] = ((uint64_t *)digest)[idx1]; ((uint64_t*)genmem)[idx2] = ((uint64_t*)digest)[idx1];
((uint64_t *)digest)[idx1] = tmp; ((uint64_t*)digest)[idx1] = tmp;
s20.crypt20(digest,digest,64); s20.crypt20(digest, digest, 64);
} }
} }
// Hashcash generation halting condition -- halt when first byte is less than // Hashcash generation halting condition -- halt when first byte is less than
// threshold value. // threshold value.
struct _Identity_generate_cond struct _Identity_generate_cond {
{ _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
{ {
_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); return (digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN);
} }
unsigned char *digest; unsigned char* digest;
char *genmem; char* genmem;
}; };
void Identity::generate() void Identity::generate()
{ {
unsigned char digest[64]; unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY]; char* genmem = new char[ZT_IDENTITY_GEN_MEMORY];
C25519::Pair kp; C25519::Pair kp;
do { do {
kp = C25519::generateSatisfying(_Identity_generate_cond(digest,genmem)); kp = C25519::generateSatisfying(_Identity_generate_cond(digest, genmem));
_address.setTo(digest + 59,ZT_ADDRESS_LENGTH); // last 5 bytes are address _address.setTo(digest + 59, ZT_ADDRESS_LENGTH); // last 5 bytes are address
} while (_address.isReserved()); } while (_address.isReserved());
_publicKey = kp.pub; _publicKey = kp.pub;
if (!_privateKey) { if (! _privateKey) {
_privateKey = new C25519::Private(); _privateKey = new C25519::Private();
} }
*_privateKey = kp.priv; *_privateKey = kp.priv;
delete [] genmem; delete[] genmem;
} }
bool Identity::locallyValidate() const bool Identity::locallyValidate() const
@ -108,60 +112,54 @@ bool Identity::locallyValidate() const
} }
unsigned char digest[64]; unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY]; char* genmem = new char[ZT_IDENTITY_GEN_MEMORY];
_computeMemoryHardHash(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem); _computeMemoryHardHash(_publicKey.data, ZT_C25519_PUBLIC_KEY_LEN, digest, genmem);
delete [] genmem; delete[] genmem;
unsigned char addrb[5]; unsigned char addrb[5];
_address.copyTo(addrb,5); _address.copyTo(addrb, 5);
return ( 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]));
(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; char* p = buf;
Utils::hex10(_address.toInt(),p); Utils::hex10(_address.toInt(), p);
p += 10; p += 10;
*(p++) = ':'; *(p++) = ':';
*(p++) = '0'; *(p++) = '0';
*(p++) = ':'; *(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; p += ZT_C25519_PUBLIC_KEY_LEN * 2;
if ((_privateKey)&&(includePrivate)) { if ((_privateKey) && (includePrivate)) {
*(p++) = ':'; *(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 += ZT_C25519_PRIVATE_KEY_LEN * 2;
} }
*p = (char)0; *p = (char)0;
return buf; return buf;
} }
bool Identity::fromString(const char *str) bool Identity::fromString(const char* str)
{ {
if (!str) { if (! str) {
_address.zero(); _address.zero();
return false; return false;
} }
char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH]; char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH];
if (!Utils::scopy(tmp,sizeof(tmp),str)) { if (! Utils::scopy(tmp, sizeof(tmp), str)) {
_address.zero(); _address.zero();
return false; return false;
} }
delete _privateKey; delete _privateKey;
_privateKey = (C25519::Private *)0; _privateKey = (C25519::Private*)0;
int fno = 0; int fno = 0;
char *saveptr = (char *)0; char* saveptr = (char*)0;
for(char *f=Utils::stok(tmp,":",&saveptr);(f);f=Utils::stok((char *)0,":",&saveptr)) { for (char* f = Utils::stok(tmp, ":", &saveptr); (f); f = Utils::stok((char*)0, ":", &saveptr)) {
switch(fno++) { switch (fno++) {
case 0: case 0:
_address = Address(Utils::hexStrToU64(f)); _address = Address(Utils::hexStrToU64(f));
if (_address.isReserved()) { if (_address.isReserved()) {
@ -170,20 +168,20 @@ bool Identity::fromString(const char *str)
} }
break; break;
case 1: case 1:
if ((f[0] != '0')||(f[1])) { if ((f[0] != '0') || (f[1])) {
_address.zero(); _address.zero();
return false; return false;
} }
break; break;
case 2: 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(); _address.zero();
return false; return false;
} }
break; break;
case 3: case 3:
_privateKey = new C25519::Private(); _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(); _address.zero();
return false; return false;
} }
@ -201,4 +199,4 @@ bool Identity::fromString(const char *str)
return true; return true;
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

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

File diff suppressed because it is too large Load diff

View file

@ -14,13 +14,13 @@
#ifndef ZT_INCOMINGPACKET_HPP #ifndef ZT_INCOMINGPACKET_HPP
#define ZT_INCOMINGPACKET_HPP #define ZT_INCOMINGPACKET_HPP
#include <stdexcept> #include "MulticastGroup.hpp"
#include "Packet.hpp" #include "Packet.hpp"
#include "Path.hpp" #include "Path.hpp"
#include "Utils.hpp"
#include "MulticastGroup.hpp"
#include "Peer.hpp" #include "Peer.hpp"
#include "Utils.hpp"
#include <stdexcept>
/* /*
* The big picture: * The big picture:
@ -46,14 +46,9 @@ class Network;
/** /**
* Subclass of packet that handles the decoding of it * Subclass of packet that handles the decoding of it
*/ */
class IncomingPacket : public Packet class IncomingPacket : public Packet {
{ public:
public: IncomingPacket() : Packet(), _receiveTime(0), _path(), _authenticated(false)
IncomingPacket() :
Packet(),
_receiveTime(0),
_path(),
_authenticated(false)
{ {
} }
@ -66,11 +61,7 @@ public:
* @param now Current time * @param now Current time
* @throws std::out_of_range Range error processing packet * @throws std::out_of_range Range error processing packet
*/ */
IncomingPacket(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now) : IncomingPacket(const void* data, unsigned int len, const SharedPtr<Path>& path, int64_t now) : Packet(data, len), _receiveTime(now), _path(path), _authenticated(false)
Packet(data,len),
_receiveTime(now),
_path(path),
_authenticated(false)
{ {
} }
@ -83,9 +74,9 @@ public:
* @param now Current time * @param now Current time
* @throws std::out_of_range Range error processing packet * @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; _receiveTime = now;
_path = path; _path = path;
_authenticated = false; _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 * @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 * @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 * @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 // These are called internally to handle packet contents once it has
// been authenticated, decrypted, decompressed, and classified. // been authenticated, decrypted, decompressed, and classified.
bool _doERROR(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 _doHELLO(const RuntimeEnvironment* RR, void* tPtr, const bool alreadyAuthenticated);
bool _doACK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doACK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doQOS_MEASUREMENT(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 _doOK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doWHOIS(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 _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 _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 _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 _doECHO(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doMULTICAST_LIKE(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_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_REQUEST(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doNETWORK_CONFIG(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_GATHER(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doMULTICAST_FRAME(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 _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 _doUSER_MESSAGE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doREMOTE_TRACE(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 _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; uint64_t _receiveTime;
SharedPtr<Path> _path; SharedPtr<Path> _path;
bool _authenticated; bool _authenticated;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -11,132 +11,132 @@
*/ */
/****/ /****/
#include <stdio.h> #include "InetAddress.hpp"
#include <string.h>
#include <stdint.h>
#include <string>
#include "Constants.hpp" #include "Constants.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
namespace ZeroTier { namespace ZeroTier {
const InetAddress InetAddress::LO4((const void *)("\x7f\x00\x00\x01"),4,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); 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 InetAddress::IpScope InetAddress::ipScope() const
{ {
switch(ss_family) { switch (ss_family) {
case AF_INET: { case AF_INET: {
const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr); const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr);
switch(ip >> 24) { switch (ip >> 24) {
case 0x00: 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: 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: case 0x0a:
return IP_SCOPE_PRIVATE; // 10.0.0.0/8 return IP_SCOPE_PRIVATE; // 10.0.0.0/8
case 0x0b: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: case 0x64:
if ((ip & 0xffc00000) == 0x64400000) { if ((ip & 0xffc00000) == 0x64400000) {
return IP_SCOPE_PRIVATE; // 100.64.0.0/10 return IP_SCOPE_PRIVATE; // 100.64.0.0/10
} }
break; break;
case 0x7f: case 0x7f:
return IP_SCOPE_LOOPBACK; // 127.0.0.0/8 return IP_SCOPE_LOOPBACK; // 127.0.0.0/8
case 0xa9: case 0xa9:
if ((ip & 0xffff0000) == 0xa9fe0000) { 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; break;
case 0xac: case 0xac:
if ((ip & 0xfff00000) == 0xac100000) { if ((ip & 0xfff00000) == 0xac100000) {
return IP_SCOPE_PRIVATE; // 172.16.0.0/12 return IP_SCOPE_PRIVATE; // 172.16.0.0/12
} }
break; break;
case 0xc0: case 0xc0:
if ((ip & 0xffff0000) == 0xc0a80000) { 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) { if ((ip & 0xffffff00) == 0xc0000200) {
return IP_SCOPE_PRIVATE; // 192.0.2.0/24 return IP_SCOPE_PRIVATE; // 192.0.2.0/24
} }
break; break;
case 0xc6: case 0xc6:
if ((ip & 0xfffe0000) == 0xc6120000) { 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) { if ((ip & 0xffffff00) == 0xc6336400) {
return IP_SCOPE_PRIVATE; // 198.51.100.0/24 return IP_SCOPE_PRIVATE; // 198.51.100.0/24
} }
break; break;
case 0xcb: case 0xcb:
if ((ip & 0xffffff00) == 0xcb007100) { if ((ip & 0xffffff00) == 0xcb007100) {
return IP_SCOPE_PRIVATE; // 203.0.113.0/24 return IP_SCOPE_PRIVATE; // 203.0.113.0/24
} }
break; break;
case 0xff: 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: case 0xe:
return IP_SCOPE_MULTICAST; // 224.0.0.0/4 return IP_SCOPE_MULTICAST; // 224.0.0.0/4
case 0xf: 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; return IP_SCOPE_GLOBAL;
} break; } break;
case AF_INET6: { 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] & 0xf0) == 0xf0) {
if (ip[0] == 0xff) { 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; unsigned int k = 2;
while ((!ip[k])&&(k < 15)) { while ((! ip[k]) && (k < 15)) {
++k; ++k;
} }
if ((k == 15)&&(ip[15] == 0x01)) { if ((k == 15) && (ip[15] == 0x01)) {
return IP_SCOPE_LOOPBACK; // fe80::1/128 return IP_SCOPE_LOOPBACK; // fe80::1/128
} else { }
return IP_SCOPE_LINK_LOCAL; // fe80::/10 else {
return IP_SCOPE_LINK_LOCAL; // fe80::/10
} }
} }
if ((ip[0] & 0xfe) == 0xfc) { if ((ip[0] & 0xfe) == 0xfc) {
return IP_SCOPE_PRIVATE; // fc00::/7 return IP_SCOPE_PRIVATE; // fc00::/7
} }
} }
// :::ffff:127.0.0.1 // :::ffff:127.0.0.1
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1 // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1
unsigned int k = 0; unsigned int k = 0;
while ((!ip[k])&&(k < 9)) { while ((! ip[k]) && (k < 9)) {
++k; ++k;
} }
if (k == 9) { if (k == 9) {
@ -146,92 +146,92 @@ InetAddress::IpScope InetAddress::ipScope() const
} }
k = 0; k = 0;
while ((!ip[k])&&(k < 15)) { while ((! ip[k]) && (k < 15)) {
++k; ++k;
} }
if (k == 15) { // all 0's except last byte if (k == 15) { // all 0's except last byte
if (ip[15] == 0x01) { if (ip[15] == 0x01) {
return IP_SCOPE_LOOPBACK; // ::1/128 return IP_SCOPE_LOOPBACK; // ::1/128
} }
if (ip[15] == 0x00) { if (ip[15] == 0x00) {
return IP_SCOPE_NONE; // ::/128 return IP_SCOPE_NONE; // ::/128
} }
} }
return IP_SCOPE_GLOBAL; return IP_SCOPE_GLOBAL;
} break; } break;
} }
return IP_SCOPE_NONE; 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) { if (ipLen == 4) {
uint32_t ipb[1]; uint32_t ipb[1];
memcpy(ipb,ipBytes,4); memcpy(ipb, ipBytes, 4);
ss_family = AF_INET; ss_family = AF_INET;
reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr = ipb[0]; 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); reinterpret_cast<struct sockaddr_in*>(this)->sin_port = Utils::hton((uint16_t)port);
} else if (ipLen == 16) { }
else if (ipLen == 16) {
ss_family = AF_INET6; ss_family = AF_INET6;
memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,ipBytes,16); 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); 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) { if (*p) {
while (*p) { while (*p) {
++p; ++p;
} }
*(p++) = '/'; *(p++) = '/';
Utils::decimal(port(),p); Utils::decimal(port(), p);
} }
return buf; return buf;
} }
char *InetAddress::toIpString(char buf[64]) const char* InetAddress::toIpString(char buf[64]) const
{ {
buf[0] = (char)0; buf[0] = (char)0;
switch(ss_family) { switch (ss_family) {
case AF_INET: { case AF_INET: {
#ifdef _WIN32 #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 #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 #endif
} break; } break;
case AF_INET6: { case AF_INET6: {
#ifdef _WIN32 #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 #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 #endif
} break; } break;
} }
return buf; return buf;
} }
bool InetAddress::fromString(const char *ipSlashPort) bool InetAddress::fromString(const char* ipSlashPort)
{ {
char buf[64]; char buf[64];
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
if (!*ipSlashPort) { if (! *ipSlashPort) {
return true; return true;
} }
if (!Utils::scopy(buf,sizeof(buf),ipSlashPort)) { if (! Utils::scopy(buf, sizeof(buf), ipSlashPort)) {
return false; return false;
} }
char *portAt = buf; char* portAt = buf;
while ((*portAt)&&(*portAt != '/')) { while ((*portAt) && (*portAt != '/')) {
++portAt; ++portAt;
} }
unsigned int port = 0; unsigned int port = 0;
@ -240,19 +240,21 @@ bool InetAddress::fromString(const char *ipSlashPort)
port = Utils::strToUInt(portAt) & 0xffff; port = Utils::strToUInt(portAt) & 0xffff;
} }
if (strchr(buf,':')) { if (strchr(buf, ':')) {
struct sockaddr_in6 *const in6 = reinterpret_cast<struct sockaddr_in6 *>(this); struct sockaddr_in6* const in6 = reinterpret_cast<struct sockaddr_in6*>(this);
inet_pton(AF_INET6, buf, &in6->sin6_addr.s6_addr); inet_pton(AF_INET6, buf, &in6->sin6_addr.s6_addr);
in6->sin6_family = AF_INET6; in6->sin6_family = AF_INET6;
in6->sin6_port = Utils::hton((uint16_t)port); in6->sin6_port = Utils::hton((uint16_t)port);
return true; 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); inet_pton(AF_INET, buf, &in->sin_addr.s_addr);
in->sin_family = AF_INET; in->sin_family = AF_INET;
in->sin_port = Utils::hton((uint16_t)port); in->sin_port = Utils::hton((uint16_t)port);
return true; return true;
} else { }
else {
return false; return false;
} }
} }
@ -260,22 +262,23 @@ bool InetAddress::fromString(const char *ipSlashPort)
InetAddress InetAddress::netmask() const InetAddress InetAddress::netmask() const
{ {
InetAddress r(*this); InetAddress r(*this);
switch(r.ss_family) { switch (r.ss_family) {
case AF_INET: 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; break;
case AF_INET6: { case AF_INET6: {
uint64_t nm[2]; uint64_t nm[2];
const unsigned int bits = netmaskBits(); const unsigned int bits = netmaskBits();
if(bits) { if (bits) {
nm[0] = Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - 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)))); nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
} else { }
else {
nm[0] = 0; nm[0] = 0;
nm[1] = 0; nm[1] = 0;
} }
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16); memcpy(reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, nm, 16);
} break; } break;
} }
return r; return r;
} }
@ -284,7 +287,7 @@ InetAddress InetAddress::broadcast() const
{ {
if (ss_family == AF_INET) { if (ss_family == AF_INET) {
InetAddress r(*this); 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 r;
} }
return InetAddress(); return InetAddress();
@ -293,34 +296,34 @@ InetAddress InetAddress::broadcast() const
InetAddress InetAddress::network() const InetAddress InetAddress::network() const
{ {
InetAddress r(*this); InetAddress r(*this);
switch(r.ss_family) { switch (r.ss_family) {
case AF_INET: 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; break;
case AF_INET6: { case AF_INET6: {
uint64_t nm[2]; uint64_t nm[2];
const unsigned int bits = netmaskBits(); 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[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - 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); memcpy(reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, nm, 16);
} break; } break;
} }
return r; return r;
} }
bool InetAddress::isEqualPrefix(const InetAddress &addr) const bool InetAddress::isEqualPrefix(const InetAddress& addr) const
{ {
if (addr.ss_family == ss_family) { if (addr.ss_family == ss_family) {
switch(ss_family) { switch (ss_family) {
case AF_INET6: { case AF_INET6: {
const InetAddress mask(netmask()); const InetAddress mask(netmask());
InetAddress addr_mask(addr.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* 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* 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* 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); 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) { for (unsigned int i = 0; i < 16; ++i) {
if ((a[i] & m[i]) != (b[i] & n[i])) { if ((a[i] & m[i]) != (b[i] & n[i])) {
return false; return false;
} }
@ -332,23 +335,24 @@ bool InetAddress::isEqualPrefix(const InetAddress &addr) const
return false; return false;
} }
bool InetAddress::containsAddress(const InetAddress &addr) const bool InetAddress::containsAddress(const InetAddress& addr) const
{ {
if (addr.ss_family == ss_family) { if (addr.ss_family == ss_family) {
switch(ss_family) { switch (ss_family) {
case AF_INET: { case AF_INET: {
const unsigned int bits = netmaskBits(); const unsigned int bits = netmaskBits();
if (bits == 0) { if (bits == 0) {
return true; 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: { case AF_INET6: {
const InetAddress mask(netmask()); 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* 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* 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); 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) { for (unsigned int i = 0; i < 16; ++i) {
if ((a[i] & m[i]) != b[i]) { if ((a[i] & m[i]) != b[i]) {
return false; return false;
} }
@ -362,7 +366,7 @@ bool InetAddress::containsAddress(const InetAddress &addr) const
bool InetAddress::isNetwork() const bool InetAddress::isNetwork() const
{ {
switch(ss_family) { switch (ss_family) {
case AF_INET: { case AF_INET: {
unsigned int bits = netmaskBits(); unsigned int bits = netmaskBits();
if (bits <= 0) { if (bits <= 0) {
@ -371,7 +375,7 @@ bool InetAddress::isNetwork() const
if (bits >= 32) { if (bits >= 32) {
return false; 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); return ((ip & (0xffffffff >> bits)) == 0);
} }
case AF_INET6: { case AF_INET6: {
@ -382,7 +386,7 @@ bool InetAddress::isNetwork() const
if (bits >= 128) { if (bits >= 128) {
return false; 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; unsigned int p = bits / 8;
if ((ip[p++] & (0xff >> (bits % 8))) != 0) { if ((ip[p++] & (0xff >> (bits % 8))) != 0) {
return false; return false;
@ -398,55 +402,60 @@ bool InetAddress::isNetwork() const
return false; return false;
} }
bool InetAddress::operator==(const InetAddress &a) const bool InetAddress::operator==(const InetAddress& a) const
{ {
if (ss_family == a.ss_family) { if (ss_family == a.ss_family) {
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
return ( 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_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_addr.s_addr == reinterpret_cast<const struct sockaddr_in*>(&a)->sin_addr.s_addr));
break; break;
case AF_INET6: case AF_INET6:
return ( 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_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)&& && (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)&& && (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_scope_id == reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_scope_id));
break; break;
default: default:
return (memcmp(this,&a,sizeof(InetAddress)) == 0); return (memcmp(this, &a, sizeof(InetAddress)) == 0);
} }
} }
return false; return false;
} }
bool InetAddress::operator<(const InetAddress &a) const bool InetAddress::operator<(const InetAddress& a) const
{ {
if (ss_family < a.ss_family) { if (ss_family < a.ss_family) {
return true; 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: 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; 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; return true;
} }
} }
break; break;
case AF_INET6: 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; 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; 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; 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; return true;
} }
} }
@ -454,13 +463,13 @@ bool InetAddress::operator<(const InetAddress &a) const
} }
break; break;
default: default:
return (memcmp(this,&a,sizeof(InetAddress)) < 0); return (memcmp(this, &a, sizeof(InetAddress)) < 0);
} }
} }
return false; return false;
} }
InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac) InetAddress InetAddress::makeIpv6LinkLocal(const MAC& mac)
{ {
struct sockaddr_in6 sin6; struct sockaddr_in6 sin6;
sin6.sin6_family = AF_INET6; sin6.sin6_family = AF_INET6;
@ -484,10 +493,10 @@ InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
return InetAddress(sin6); return InetAddress(sin6);
} }
InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress) InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress)
{ {
InetAddress r; 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_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfd; sin6->sin6_addr.s6_addr[0] = 0xfd;
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56); 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[13] = (uint8_t)(zeroTierAddress >> 16);
sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8); sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8);
sin6->sin6_addr.s6_addr[15] = (uint8_t)zeroTierAddress; 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; return r;
} }
InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress) InetAddress InetAddress::makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress)
{ {
nwid ^= (nwid >> 32); nwid ^= (nwid >> 32);
InetAddress r; 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_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfc; sin6->sin6_addr.s6_addr[0] = 0xfc;
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24); 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; return r;
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,15 +14,15 @@
#ifndef ZT_INETADDRESS_HPP #ifndef ZT_INETADDRESS_HPP
#define 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 <stdlib.h>
#include <string.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 { namespace ZeroTier {
@ -39,8 +39,7 @@ namespace ZeroTier {
* sockaddr_storage and used interchangeably. DO NOT change this by e.g. * sockaddr_storage and used interchangeably. DO NOT change this by e.g.
* adding non-static fields, since much code depends on this identity. * 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) * 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 * MUST remain that way or Path must be changed to reflect. Also be sure
* to change ZT_INETADDRESS_MAX_SCOPE if the max changes. * to change ZT_INETADDRESS_MAX_SCOPE if the max changes.
*/ */
enum IpScope enum IpScope {
{ IP_SCOPE_NONE = 0, // NULL or not an IP address
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_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc.
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_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_GLOBAL = 4, // globally routable IP address (all others) IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL
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_SHARED = 6, // currently unused, formerly used for carrier-grade NAT ranges IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc.
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 // 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. // but this is safe to put here.
struct Hasher struct Hasher {
{ inline std::size_t operator()(const InetAddress& a) const
inline std::size_t operator()(const InetAddress &a) const { return (std::size_t)a.hashCode(); } {
return (std::size_t)a.hashCode();
}
}; };
InetAddress() { memset(this,0,sizeof(InetAddress)); } InetAddress()
InetAddress(const InetAddress &a) { memcpy(this,&a,sizeof(InetAddress)); } {
InetAddress(const InetAddress *a) { memcpy(this,a,sizeof(InetAddress)); } memset(this, 0, sizeof(InetAddress));
InetAddress(const struct sockaddr_storage &ss) { *this = ss; } }
InetAddress(const struct sockaddr_storage *ss) { *this = ss; } InetAddress(const InetAddress& a)
InetAddress(const struct sockaddr &sa) { *this = sa; } {
InetAddress(const struct sockaddr *sa) { *this = sa; } memcpy(this, &a, sizeof(InetAddress));
InetAddress(const struct sockaddr_in &sa) { *this = sa; } }
InetAddress(const struct sockaddr_in *sa) { *this = sa; } InetAddress(const InetAddress* a)
InetAddress(const struct sockaddr_in6 &sa) { *this = sa; } {
InetAddress(const struct sockaddr_in6 *sa) { *this = sa; } memcpy(this, a, sizeof(InetAddress));
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 struct sockaddr_storage& ss)
InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); } {
*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) { if (&a != this) {
memcpy(this,&a,sizeof(InetAddress)); memcpy(this, &a, sizeof(InetAddress));
} }
return *this; return *this;
} }
inline InetAddress &operator=(const InetAddress *a) inline InetAddress& operator=(const InetAddress* a)
{ {
if (a != this) { if (a != this) {
memcpy(this,a,sizeof(InetAddress)); memcpy(this, a, sizeof(InetAddress));
} }
return *this; 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) { if (reinterpret_cast<const InetAddress*>(&ss) != this) {
memcpy(this,&ss,sizeof(InetAddress)); memcpy(this, &ss, sizeof(InetAddress));
} }
return *this; 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) { if (reinterpret_cast<const InetAddress*>(ss) != this) {
memcpy(this,ss,sizeof(InetAddress)); memcpy(this, ss, sizeof(InetAddress));
} }
return *this; 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) { if (reinterpret_cast<const InetAddress*>(&sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in)); memcpy(this, &sa, sizeof(struct sockaddr_in));
} }
return *this; 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) { if (reinterpret_cast<const InetAddress*>(sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
memcpy(this,sa,sizeof(struct sockaddr_in)); memcpy(this, sa, sizeof(struct sockaddr_in));
} }
return *this; 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) { if (reinterpret_cast<const InetAddress*>(&sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in6)); memcpy(this, &sa, sizeof(struct sockaddr_in6));
} }
return *this; 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) { if (reinterpret_cast<const InetAddress*>(sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
memcpy(this,sa,sizeof(struct sockaddr_in6)); memcpy(this, sa, sizeof(struct sockaddr_in6));
} }
return *this; return *this;
} }
inline InetAddress &operator=(const struct sockaddr &sa) inline InetAddress& operator=(const struct sockaddr& sa)
{ {
if (reinterpret_cast<const InetAddress *>(&sa) != this) { if (reinterpret_cast<const InetAddress*>(&sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
switch(sa.sa_family) { switch (sa.sa_family) {
case AF_INET: case AF_INET:
memcpy(this,&sa,sizeof(struct sockaddr_in)); memcpy(this, &sa, sizeof(struct sockaddr_in));
break; break;
case AF_INET6: case AF_INET6:
memcpy(this,&sa,sizeof(struct sockaddr_in6)); memcpy(this, &sa, sizeof(struct sockaddr_in6));
break; break;
} }
} }
return *this; return *this;
} }
inline InetAddress &operator=(const struct sockaddr *sa) inline InetAddress& operator=(const struct sockaddr* sa)
{ {
if (reinterpret_cast<const InetAddress *>(sa) != this) { if (reinterpret_cast<const InetAddress*>(sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
switch(sa->sa_family) { switch (sa->sa_family) {
case AF_INET: case AF_INET:
memcpy(this,sa,sizeof(struct sockaddr_in)); memcpy(this, sa, sizeof(struct sockaddr_in));
break; break;
case AF_INET6: case AF_INET6:
memcpy(this,sa,sizeof(struct sockaddr_in6)); memcpy(this, sa, sizeof(struct sockaddr_in6));
break; break;
} }
} }
@ -204,7 +246,7 @@ struct InetAddress : public sockaddr_storage
* @param ipLen Length of IP address: 4 or 16 * @param ipLen Length of IP address: 4 or 16
* @param port Port number or 0 for none * @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 * Set the port component
@ -213,12 +255,12 @@ struct InetAddress : public sockaddr_storage
*/ */
inline void setPort(unsigned int port) inline void setPort(unsigned int port)
{ {
switch(ss_family) { switch (ss_family) {
case AF_INET: 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; break;
case AF_INET6: 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; break;
} }
} }
@ -228,17 +270,17 @@ struct InetAddress : public sockaddr_storage
*/ */
inline bool isDefaultRoute() const inline bool isDefaultRoute() const
{ {
switch(ss_family) { switch (ss_family) {
case AF_INET: 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: case AF_INET6:
const uint8_t *ipb = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr); 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) { for (int i = 0; i < 16; ++i) {
if (ipb[i]) { if (ipb[i]) {
return false; 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; return false;
} }
@ -246,29 +288,29 @@ struct InetAddress : public sockaddr_storage
/** /**
* @return ASCII IP/port format representation * @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 * @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) * @param ipSlashPort IP/port (port is optional, will be 0 if not included)
* @return True if address appeared to be valid * @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 * @return Port or 0 if no port component defined
*/ */
inline unsigned int port() const inline unsigned int port() const
{ {
switch(ss_family) { switch (ss_family) {
case AF_INET: 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: 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: default:
return 0; return 0;
} }
@ -283,7 +325,10 @@ struct InetAddress : public sockaddr_storage
* *
* @return Netmask bits * @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 * @return True if netmask bits is valid for the address type
@ -291,7 +336,7 @@ struct InetAddress : public sockaddr_storage
inline bool netmaskBitsValid() const inline bool netmaskBitsValid() const
{ {
const unsigned int n = port(); const unsigned int n = port();
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
return (n <= 32); return (n <= 32);
case AF_INET6: case AF_INET6:
@ -308,7 +353,10 @@ struct InetAddress : public sockaddr_storage
* *
* @return Gateway metric * @return Gateway metric
*/ */
inline unsigned int metric() const { return port(); } inline unsigned int metric() const
{
return port();
}
/** /**
* Construct a full netmask as an InetAddress * Construct a full netmask as an InetAddress
@ -340,7 +388,7 @@ struct InetAddress : public sockaddr_storage
* @param addr Address to check * @param addr Address to check
* @return True if this IPv6 prefix matches the prefix of a given IPv6 address * @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 * Test whether this IP/netmask contains this address
@ -348,28 +396,34 @@ struct InetAddress : public sockaddr_storage
* @param addr Address to check * @param addr Address to check
* @return True if this IP/netmask (route) contains this address * @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 * @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 * @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 * @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: 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: 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: default:
return 0; return 0;
} }
@ -381,14 +435,14 @@ struct InetAddress : public sockaddr_storage
inline InetAddress ipOnly() const inline InetAddress ipOnly() const
{ {
InetAddress r; InetAddress r;
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
r.ss_family = 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; break;
case AF_INET6: case AF_INET6:
r.ss_family = 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; break;
} }
return r; return r;
@ -400,16 +454,16 @@ struct InetAddress : public sockaddr_storage
* @param a InetAddress to compare again * @param a InetAddress to compare again
* @return True if only IP portions are equal (false for non-IP or null addresses) * @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 == a.ss_family) {
if (ss_family == AF_INET) { 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) { 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; return false;
} }
@ -422,16 +476,16 @@ struct InetAddress : public sockaddr_storage
* @param a InetAddress to compare again * @param a InetAddress to compare again
* @return True if only IP portions are equal (false for non-IP or null addresses) * @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 == a.ss_family) {
if (ss_family == AF_INET) { 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) { 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; return false;
} }
@ -439,19 +493,21 @@ struct InetAddress : public sockaddr_storage
inline unsigned long hashCode() const inline unsigned long hashCode() const
{ {
if (ss_family == AF_INET) { 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); 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; else if (ss_family == AF_INET6) {
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr); unsigned long tmp = reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port;
for(long i=0;i<16;++i) { const uint8_t* a = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
reinterpret_cast<uint8_t *>(&tmp)[i % sizeof(tmp)] ^= a[i]; for (long i = 0; i < 16; ++i) {
reinterpret_cast<uint8_t*>(&tmp)[i % sizeof(tmp)] ^= a[i];
} }
return tmp; return tmp;
} else { }
unsigned long tmp = reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port; else {
const uint8_t *a = reinterpret_cast<const uint8_t *>(this); unsigned long tmp = reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port;
for(long i=0;i<(long)sizeof(InetAddress);++i) { const uint8_t* a = reinterpret_cast<const uint8_t*>(this);
reinterpret_cast<uint8_t *>(&tmp)[i % sizeof(tmp)] ^= a[i]; for (long i = 0; i < (long)sizeof(InetAddress); ++i) {
reinterpret_cast<uint8_t*>(&tmp)[i % sizeof(tmp)] ^= a[i];
} }
return tmp; return tmp;
} }
@ -460,7 +516,10 @@ struct InetAddress : public sockaddr_storage
/** /**
* Set to null/zero * 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 * 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 * Find the total number of prefix bits that match between this IP and another
* *
* @param b Second IP to compare with * @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) * @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; unsigned int c = 0;
if (ss_family == b.ss_family) { if (ss_family == b.ss_family) {
switch(ss_family) { switch (ss_family) {
case AF_INET: { case AF_INET: {
uint32_t ip0 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->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); uint32_t ip1 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(&b)->sin_addr.s_addr);
while ((ip0 >> 31) == (ip1 >> 31)) { while ((ip0 >> 31) == (ip1 >> 31)) {
ip0 <<= 1; ip0 <<= 1;
ip1 <<= 1; ip1 <<= 1;
@ -493,14 +552,15 @@ struct InetAddress : public sockaddr_storage
break; break;
} }
} }
} break; } break;
case AF_INET6: { 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* 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); 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) { for (unsigned int i = 0; i < 16; ++i) {
if (ip0[i] == ip1[i]) { if (ip0[i] == ip1[i]) {
c += 8; c += 8;
} else { }
else {
uint8_t ip0b = ip0[i]; uint8_t ip0b = ip0[i];
uint8_t ip1b = ip1[i]; uint8_t ip1b = ip1[i];
uint8_t bit = 0x80; uint8_t bit = 0x80;
@ -514,7 +574,7 @@ struct InetAddress : public sockaddr_storage
break; break;
} }
} }
} break; } break;
} }
} }
return c; return c;
@ -526,13 +586,13 @@ struct InetAddress : public sockaddr_storage
inline unsigned long rateGateHash() const inline unsigned long rateGateHash() const
{ {
unsigned long h = 0; unsigned long h = 0;
switch(ss_family) { switch (ss_family) {
case AF_INET: 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); h ^= (h >> 14);
break; break;
case AF_INET6: { 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 = ((unsigned long)ip[0]);
h <<= 1; h <<= 1;
h += ((unsigned long)ip[1]); h += ((unsigned long)ip[1]);
@ -544,7 +604,7 @@ struct InetAddress : public sockaddr_storage
h += ((unsigned long)ip[4]); h += ((unsigned long)ip[4]);
h <<= 1; h <<= 1;
h += ((unsigned long)ip[5]); h += ((unsigned long)ip[5]);
} break; } break;
} }
return (h & 0x3fff); return (h & 0x3fff);
} }
@ -552,23 +612,25 @@ struct InetAddress : public sockaddr_storage
/** /**
* @return True if address family is non-zero * @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> template <unsigned int C> inline void serialize(Buffer<C>& b) const
inline void serialize(Buffer<C> &b) const
{ {
// This is used in the protocol and must be the same as describe in places // This is used in the protocol and must be the same as describe in places
// like VERB_HELLO in Packet.hpp. // like VERB_HELLO in Packet.hpp.
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
b.append((uint8_t)0x04); b.append((uint8_t)0x04);
b.append(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr),4); 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((uint16_t)port()); // just in case sin_port != uint16_t
return; return;
case AF_INET6: case AF_INET6:
b.append((uint8_t)0x06); b.append((uint8_t)0x06);
b.append(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16); 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((uint16_t)port()); // just in case sin_port != uint16_t
return; return;
default: default:
b.append((uint8_t)0); b.append((uint8_t)0);
@ -576,12 +638,11 @@ struct InetAddress : public sockaddr_storage
} }
} }
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
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; unsigned int p = startAt;
switch(b[p++]) { switch (b[p++]) {
case 0: case 0:
return 1; return 1;
case 0x01: case 0x01:
@ -593,19 +654,19 @@ struct InetAddress : public sockaddr_storage
case 0x03: case 0x03:
// TODO: Other address types (but accept for forward compatibility) // TODO: Other address types (but accept for forward compatibility)
// These could be extended/optional things like AF_UNIX, LTE Direct, shared memory, etc. // 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: case 0x04:
ss_family = AF_INET; 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; 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; p += 2;
break; break;
case 0x06: case 0x06:
ss_family = AF_INET6; 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; 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; p += 2;
break; break;
default: default:
@ -614,18 +675,30 @@ struct InetAddress : public sockaddr_storage
return (p - startAt); return (p - startAt);
} }
bool operator==(const InetAddress &a) const; bool operator==(const InetAddress& a) const;
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
inline bool operator>(const InetAddress &a) const { return (a < *this); } {
inline bool operator<=(const InetAddress &a) const { return !(a < *this); } return ! (*this == a);
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 * @param mac MAC address seed
* @return IPv6 link-local address * @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 * 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) * @param zeroTierAddress 40-bit device address (in least significant 40 bits, highest 24 bits ignored)
* @return IPv6 private unicast address with /88 netmask * @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 * 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 #endif

View file

@ -14,64 +14,81 @@
#ifndef ZT_MAC_HPP #ifndef ZT_MAC_HPP
#define 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 "Address.hpp"
#include "Buffer.hpp" #include "Buffer.hpp"
#include "Constants.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
namespace ZeroTier { namespace ZeroTier {
/** /**
* 48-byte Ethernet MAC address * 48-byte Ethernet MAC address
*/ */
class MAC class MAC {
{ public:
public: MAC() : _m(0ULL)
MAC() : _m(0ULL) {} {
MAC(const MAC &m) : _m(m._m) {} }
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) : 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) | : _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))
((((uint64_t)b) & 0xffULL) << 32) | {
((((uint64_t)c) & 0xffULL) << 24) | }
((((uint64_t)d) & 0xffULL) << 16) | MAC(const void* bits, unsigned int len)
((((uint64_t)e) & 0xffULL) << 8) | {
(((uint64_t)f) & 0xffULL) ) {} setTo(bits, len);
MAC(const void *bits,unsigned int len) { setTo(bits,len); } }
MAC(const Address &ztaddr,uint64_t nwid) { fromAddress(ztaddr,nwid); } MAC(const Address& ztaddr, uint64_t nwid)
MAC(const uint64_t m) : _m(m & 0xffffffffffffULL) {} {
fromAddress(ztaddr, nwid);
}
MAC(const uint64_t m) : _m(m & 0xffffffffffffULL)
{
}
/** /**
* @return MAC in 64-bit integer * @return MAC in 64-bit integer
*/ */
inline uint64_t toInt() const { return _m; } inline uint64_t toInt() const
{
return _m;
}
/** /**
* Set MAC to zero * Set MAC to zero
*/ */
inline void zero() { _m = 0ULL; } inline void zero()
{
_m = 0ULL;
}
/** /**
* @return True if MAC is non-zero * @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 bits Raw MAC in big-endian byte order
* @param len Length, must be >= 6 or result is zero * @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) { if (len < 6) {
_m = 0ULL; _m = 0ULL;
return; return;
} }
const unsigned char *b = (const unsigned char *)bits; const unsigned char* b = (const unsigned char*)bits;
_m = ((((uint64_t)*b) & 0xff) << 40); _m = ((((uint64_t)*b) & 0xff) << 40);
++b; ++b;
_m |= ((((uint64_t)*b) & 0xff) << 32); _m |= ((((uint64_t)*b) & 0xff) << 32);
++b; ++b;
@ -88,12 +105,12 @@ public:
* @param buf Destination buffer for MAC in big-endian byte order * @param buf Destination buffer for MAC in big-endian byte order
* @param len Length of buffer, must be >= 6 or nothing is copied * @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) { if (len < 6) {
return; return;
} }
unsigned char *b = (unsigned char *)buf; unsigned char* b = (unsigned char*)buf;
*(b++) = (unsigned char)((_m >> 40) & 0xff); *(b++) = (unsigned char)((_m >> 40) & 0xff);
*(b++) = (unsigned char)((_m >> 32) & 0xff); *(b++) = (unsigned char)((_m >> 32) & 0xff);
*(b++) = (unsigned char)((_m >> 24) & 0xff); *(b++) = (unsigned char)((_m >> 24) & 0xff);
@ -107,10 +124,9 @@ public:
* *
* @param b Buffer to append to * @param b Buffer to append to
*/ */
template<unsigned int C> template <unsigned int C> inline void appendTo(Buffer<C>& b) const
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 >> 40) & 0xff);
*(p++) = (unsigned char)((_m >> 32) & 0xff); *(p++) = (unsigned char)((_m >> 32) & 0xff);
*(p++) = (unsigned char)((_m >> 24) & 0xff); *(p++) = (unsigned char)((_m >> 24) & 0xff);
@ -122,17 +138,26 @@ public:
/** /**
* @return True if this is broadcast (all 0xff) * @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 * @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 * @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 * Set this MAC to a MAC derived from an address and a network ID
@ -140,10 +165,10 @@ public:
* @param ztaddr ZeroTier address * @param ztaddr ZeroTier address
* @param nwid 64-bit network ID * @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; 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 >> 8) & 0xff) << 32;
m ^= ((nwid >> 16) & 0xff) << 24; m ^= ((nwid >> 16) & 0xff) << 24;
m ^= ((nwid >> 24) & 0xff) << 16; m ^= ((nwid >> 24) & 0xff) << 16;
@ -161,8 +186,8 @@ public:
*/ */
inline Address toAddress(uint64_t nwid) const inline Address toAddress(uint64_t nwid) const
{ {
uint64_t a = _m & 0xffffffffffULL; // least significant 40 bits of MAC are formed from address 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 >> 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 >> 16) & 0xff) << 24;
a ^= ((nwid >> 24) & 0xff) << 16; a ^= ((nwid >> 24) & 0xff) << 16;
a ^= ((nwid >> 32) & 0xff) << 8; a ^= ((nwid >> 32) & 0xff) << 8;
@ -176,24 +201,33 @@ public:
*/ */
static inline unsigned char firstOctetForNetwork(uint64_t nwid) 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 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 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) * @param i Value from 0 to 5 (inclusive)
* @return Byte at said position (address interpreted in big-endian order) * @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 * @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[0] = Utils::HEXCHARS[(_m >> 44) & 0xf];
buf[1] = Utils::HEXCHARS[(_m >> 40) & 0xf]; buf[1] = Utils::HEXCHARS[(_m >> 40) & 0xf];
@ -216,28 +250,46 @@ public:
return buf; return buf;
} }
inline MAC &operator=(const MAC &m) inline MAC& operator=(const MAC& m)
{ {
_m = m._m; _m = m._m;
return *this; return *this;
} }
inline MAC &operator=(const uint64_t m) inline MAC& operator=(const uint64_t m)
{ {
_m = m; _m = m;
return *this; return *this;
} }
inline bool operator==(const MAC &m) const { return (_m == m._m); } inline bool operator==(const MAC& m) const
inline bool operator!=(const MAC &m) const { return (_m != m._m); } {
inline bool operator<(const MAC &m) const { return (_m < m._m); } 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
inline bool operator>=(const MAC &m) const { return (_m >= m._m); } {
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; uint64_t _m;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -11,47 +11,41 @@
*/ */
/****/ /****/
#include <algorithm>
#include "Membership.hpp" #include "Membership.hpp"
#include "RuntimeEnvironment.hpp"
#include "Peer.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Packet.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
#include "Trace.hpp" #include "Trace.hpp"
#include <algorithm>
namespace ZeroTier { namespace ZeroTier {
Membership::Membership() : Membership::Membership() : _lastUpdatedMulticast(0), _comRevocationThreshold(0), _lastPushedCredentials(0), _revocations(4), _remoteTags(4), _remoteCaps(4), _remoteCoos(4)
_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; 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]); sendCaps[sendCapCount++] = &(nconf.capabilities[c]);
} }
const Tag *sendTags[ZT_MAX_NETWORK_TAGS]; const Tag* sendTags[ZT_MAX_NETWORK_TAGS];
unsigned int sendTagCount = 0; 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]); 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; 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]); 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 tagPtr = 0;
unsigned int cooPtr = 0; unsigned int cooPtr = 0;
bool sendCom = (bool)(nconf.com); bool sendCom = (bool)(nconf.com);
while ((capPtr < sendCapCount)||(tagPtr < sendTagCount)||(cooPtr < sendCooCount)||(sendCom)) { while ((capPtr < sendCapCount) || (tagPtr < sendTagCount) || (cooPtr < sendCooCount) || (sendCom)) {
Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); Packet outp(peerAddress, RR->identity.address(), Packet::VERB_NETWORK_CREDENTIALS);
if (sendCom) { if (sendCom) {
sendCom = false; sendCom = false;
@ -71,20 +65,20 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
const unsigned int capCountAt = outp.size(); const unsigned int capCountAt = outp.size();
outp.addSize(2); outp.addSize(2);
unsigned int thisPacketCapCount = 0; 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); sendCaps[capPtr++]->serialize(outp);
++thisPacketCapCount; ++thisPacketCapCount;
} }
outp.setAt(capCountAt,(uint16_t)thisPacketCapCount); outp.setAt(capCountAt, (uint16_t)thisPacketCapCount);
const unsigned int tagCountAt = outp.size(); const unsigned int tagCountAt = outp.size();
outp.addSize(2); outp.addSize(2);
unsigned int thisPacketTagCount = 0; 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); sendTags[tagPtr++]->serialize(outp);
++thisPacketTagCount; ++thisPacketTagCount;
} }
outp.setAt(tagCountAt,(uint16_t)thisPacketTagCount); outp.setAt(tagCountAt, (uint16_t)thisPacketTagCount);
// No revocations, these propagate differently // No revocations, these propagate differently
outp.append((uint16_t)0); 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(); const unsigned int cooCountAt = outp.size();
outp.addSize(2); outp.addSize(2);
unsigned int thisPacketCooCount = 0; 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); sendCoos[cooPtr++]->serialize(outp);
++thisPacketCooCount; ++thisPacketCooCount;
} }
outp.setAt(cooCountAt,(uint16_t)thisPacketCooCount); outp.setAt(cooCountAt, (uint16_t)thisPacketCooCount);
outp.compress(); outp.compress();
RR->sw->send(tPtr,outp,true); RR->sw->send(tPtr, outp, true);
Metrics::pkt_network_credentials_out++; Metrics::pkt_network_credentials_out++;
} }
_lastPushedCredentials = now; _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(); const int64_t newts = com.timestamp();
if (newts <= _comRevocationThreshold) { if (newts <= _comRevocationThreshold) {
RR->t->credentialRejected(tPtr,com,"revoked"); RR->t->credentialRejected(tPtr, com, "revoked");
return ADD_REJECTED; return ADD_REJECTED;
} }
const int64_t oldts = _com.timestamp(); const int64_t oldts = _com.timestamp();
if (newts < oldts) { if (newts < oldts) {
RR->t->credentialRejected(tPtr,com,"old"); RR->t->credentialRejected(tPtr, com, "old");
return ADD_REJECTED; return ADD_REJECTED;
} }
if (_com == com) { if (_com == com) {
return ADD_ACCEPTED_REDUNDANT; return ADD_ACCEPTED_REDUNDANT;
} }
switch(com.verify(RR,tPtr)) { switch (com.verify(RR, tPtr)) {
default: default:
RR->t->credentialRejected(tPtr,com,"invalid"); RR->t->credentialRejected(tPtr, com, "invalid");
return ADD_REJECTED; return ADD_REJECTED;
case 0: 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; _com = com;
return ADD_ACCEPTED_NEW; return ADD_ACCEPTED_NEW;
case 1: case 1:
@ -137,13 +131,13 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
} }
// Template out addCredential() for many cred types to avoid copypasta // Template out addCredential() for many cred types to avoid copypasta
template<typename C> 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) 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) {
if (rc->timestamp() > cred.timestamp()) { if (rc->timestamp() > cred.timestamp()) {
RR->t->credentialRejected(tPtr,cred,"old"); RR->t->credentialRejected(tPtr, cred, "old");
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
if (*rc == cred) { 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())); const int64_t* const rt = revocations.get(Membership::credentialKey(C::credentialType(), cred.id()));
if ((rt)&&(*rt >= cred.timestamp())) { if ((rt) && (*rt >= cred.timestamp())) {
RR->t->credentialRejected(tPtr,cred,"revoked"); RR->t->credentialRejected(tPtr, cred, "revoked");
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
switch(cred.verify(RR,tPtr)) { switch (cred.verify(RR, tPtr)) {
default: default:
RR->t->credentialRejected(tPtr,cred,"invalid"); RR->t->credentialRejected(tPtr, cred, "invalid");
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
case 0: case 0:
if (!rc) { if (! rc) {
rc = &(remoteCreds[cred.id()]); rc = &(remoteCreds[cred.id()]);
} }
*rc = cred; *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 Tag& 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; return _addCredImpl<Tag>(_remoteTags, _revocations, RR, tPtr, nconf, tag);
switch(rev.verify(RR,tPtr)) { }
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: default:
RR->t->credentialRejected(tPtr,rev,"invalid"); RR->t->credentialRejected(tPtr, rev, "invalid");
return ADD_REJECTED; return ADD_REJECTED;
case 0: { case 0: {
const Credential::Type ct = rev.type(); const Credential::Type ct = rev.type();
switch(ct) { switch (ct) {
case Credential::CREDENTIAL_TYPE_COM: case Credential::CREDENTIAL_TYPE_COM:
if (rev.threshold() > _comRevocationThreshold) { if (rev.threshold() > _comRevocationThreshold) {
_comRevocationThreshold = rev.threshold(); _comRevocationThreshold = rev.threshold();
@ -195,7 +198,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
case Credential::CREDENTIAL_TYPE_CAPABILITY: case Credential::CREDENTIAL_TYPE_CAPABILITY:
case Credential::CREDENTIAL_TYPE_TAG: case Credential::CREDENTIAL_TYPE_TAG:
case Credential::CREDENTIAL_TYPE_COO: case Credential::CREDENTIAL_TYPE_COO:
rt = &(_revocations[credentialKey(ct,rev.credentialId())]); rt = &(_revocations[credentialKey(ct, rev.credentialId())]);
if (*rt < rev.threshold()) { if (*rt < rev.threshold()) {
*rt = rev.threshold(); *rt = rev.threshold();
_comRevocationThreshold = rev.threshold(); _comRevocationThreshold = rev.threshold();
@ -203,7 +206,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
} }
return ADD_ACCEPTED_REDUNDANT; return ADD_ACCEPTED_REDUNDANT;
default: default:
RR->t->credentialRejected(tPtr,rev,"invalid"); RR->t->credentialRejected(tPtr, rev, "invalid");
return ADD_REJECTED; 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<Tag>(nconf, _remoteTags);
_cleanCredImpl<Capability>(nconf,_remoteCaps); _cleanCredImpl<Capability>(nconf, _remoteCaps);
_cleanCredImpl<CertificateOfOwnership>(nconf,_remoteCoos); _cleanCredImpl<CertificateOfOwnership>(nconf, _remoteCoos);
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

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

View file

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

View file

@ -12,155 +12,152 @@
#ifndef METRICS_H_ #ifndef METRICS_H_
#define METRICS_H_ #define METRICS_H_
#include <prometheus/simpleapi.h>
#include <prometheus/histogram.h> #include <prometheus/histogram.h>
#include <prometheus/simpleapi.h>
namespace prometheus { namespace prometheus {
namespace simpleapi { namespace simpleapi {
extern std::shared_ptr<Registry> registry_ptr; extern std::shared_ptr<Registry> registry_ptr;
}
} }
} // namespace prometheus
namespace ZeroTier { namespace ZeroTier {
namespace Metrics { namespace Metrics {
// Packet Type Counts // Packet Type Counts
extern prometheus::simpleapi::counter_family_t packets; extern prometheus::simpleapi::counter_family_t packets;
// incoming packets // incoming packets
extern prometheus::simpleapi::counter_metric_t pkt_nop_in; 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_error_in;
extern prometheus::simpleapi::counter_metric_t pkt_ack_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_qos_in;
extern prometheus::simpleapi::counter_metric_t pkt_hello_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_ok_in;
extern prometheus::simpleapi::counter_metric_t pkt_whois_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_rendezvous_in;
extern prometheus::simpleapi::counter_metric_t pkt_frame_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_ext_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_echo_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_multicast_like_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_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_request_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_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_gather_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_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_push_direct_paths_in;
extern prometheus::simpleapi::counter_metric_t pkt_user_message_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_remote_trace_in;
extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in; extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in;
// outgoing packets // outgoing packets
extern prometheus::simpleapi::counter_metric_t pkt_nop_out; 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_error_out;
extern prometheus::simpleapi::counter_metric_t pkt_ack_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_qos_out;
extern prometheus::simpleapi::counter_metric_t pkt_hello_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_ok_out;
extern prometheus::simpleapi::counter_metric_t pkt_whois_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_rendezvous_out;
extern prometheus::simpleapi::counter_metric_t pkt_frame_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_ext_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_echo_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_multicast_like_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_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_request_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_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_gather_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_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_push_direct_paths_out;
extern prometheus::simpleapi::counter_metric_t pkt_user_message_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_remote_trace_out;
extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out; extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out;
// Packet Error Counts // Packet Error Counts
extern prometheus::simpleapi::counter_family_t packet_errors; extern prometheus::simpleapi::counter_family_t packet_errors;
// incoming errors // incoming errors
extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in; 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_unsupported_op_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_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_need_membership_cert_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_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_unwanted_multicast_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in; extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in; extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in;
// outgoing errors // outgoing errors
extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out; 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_unsupported_op_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_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_need_membership_cert_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_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_unwanted_multicast_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out; extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out; extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out;
// Data Sent/Received Metrics // Data Sent/Received Metrics
extern prometheus::simpleapi::counter_family_t data; extern prometheus::simpleapi::counter_family_t data;
extern prometheus::simpleapi::counter_metric_t udp_send; extern prometheus::simpleapi::counter_metric_t udp_send;
extern prometheus::simpleapi::counter_metric_t udp_recv; extern prometheus::simpleapi::counter_metric_t udp_recv;
extern prometheus::simpleapi::counter_metric_t tcp_send; extern prometheus::simpleapi::counter_metric_t tcp_send;
extern prometheus::simpleapi::counter_metric_t tcp_recv; extern prometheus::simpleapi::counter_metric_t tcp_recv;
// Network Metrics // Network Metrics
extern prometheus::simpleapi::gauge_metric_t network_num_joined; extern prometheus::simpleapi::gauge_metric_t network_num_joined;
extern prometheus::simpleapi::gauge_family_t network_num_multicast_groups; extern prometheus::simpleapi::gauge_family_t network_num_multicast_groups;
extern prometheus::simpleapi::counter_family_t network_packets; extern prometheus::simpleapi::counter_family_t network_packets;
#ifndef ZT_NO_PEER_METRICS #ifndef ZT_NO_PEER_METRICS
// Peer Metrics // Peer Metrics
extern prometheus::CustomFamily<prometheus::Histogram<uint64_t>> &peer_latency; extern prometheus::CustomFamily<prometheus::Histogram<uint64_t> >& peer_latency;
extern prometheus::simpleapi::gauge_family_t peer_path_count; extern prometheus::simpleapi::gauge_family_t peer_path_count;
extern prometheus::simpleapi::counter_family_t peer_packets; extern prometheus::simpleapi::counter_family_t peer_packets;
extern prometheus::simpleapi::counter_family_t peer_packet_errors; extern prometheus::simpleapi::counter_family_t peer_packet_errors;
#endif #endif
// General Controller Metrics // General Controller Metrics
extern prometheus::simpleapi::gauge_metric_t network_count; extern prometheus::simpleapi::gauge_metric_t network_count;
extern prometheus::simpleapi::gauge_metric_t member_count; extern prometheus::simpleapi::gauge_metric_t member_count;
extern prometheus::simpleapi::counter_metric_t network_changes; extern prometheus::simpleapi::counter_metric_t network_changes;
extern prometheus::simpleapi::counter_metric_t member_changes; extern prometheus::simpleapi::counter_metric_t member_changes;
extern prometheus::simpleapi::counter_metric_t member_auths; extern prometheus::simpleapi::counter_metric_t member_auths;
extern prometheus::simpleapi::counter_metric_t member_deauths; extern prometheus::simpleapi::counter_metric_t member_deauths;
extern prometheus::simpleapi::gauge_metric_t network_config_request_queue_size; 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_expiration_checks;
extern prometheus::simpleapi::counter_metric_t sso_member_deauth; extern prometheus::simpleapi::counter_metric_t sso_member_deauth;
extern prometheus::simpleapi::counter_metric_t network_config_request; extern prometheus::simpleapi::counter_metric_t network_config_request;
extern prometheus::simpleapi::gauge_metric_t network_config_request_threads; 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::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 #ifdef ZT_CONTROLLER_USE_LIBPQ
// Central Controller Metrics // Central Controller Metrics
extern prometheus::simpleapi::counter_metric_t pgsql_mem_notification; 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_net_notification;
extern prometheus::simpleapi::counter_metric_t pgsql_node_checkin; extern prometheus::simpleapi::counter_metric_t pgsql_node_checkin;
extern prometheus::simpleapi::counter_metric_t pgsql_commit_ticks; 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 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;
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 // Central DB Pool Metrics
extern prometheus::simpleapi::counter_metric_t conn_counter; extern prometheus::simpleapi::counter_metric_t conn_counter;
extern prometheus::simpleapi::counter_metric_t max_pool_size; extern prometheus::simpleapi::counter_metric_t max_pool_size;
extern prometheus::simpleapi::counter_metric_t min_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_avail;
extern prometheus::simpleapi::gauge_metric_t pool_in_use; extern prometheus::simpleapi::gauge_metric_t pool_in_use;
extern prometheus::simpleapi::counter_metric_t pool_errors; extern prometheus::simpleapi::counter_metric_t pool_errors;
#endif #endif
} // namespace Metrics } // namespace Metrics
}// namespace ZeroTier } // namespace ZeroTier
#endif // METRICS_H_ #endif // METRICS_H_

View file

@ -14,10 +14,10 @@
#ifndef ZT_MULTICASTGROUP_HPP #ifndef ZT_MULTICASTGROUP_HPP
#define ZT_MULTICASTGROUP_HPP #define ZT_MULTICASTGROUP_HPP
#include <stdint.h>
#include "MAC.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "MAC.hpp"
#include <stdint.h>
namespace ZeroTier { namespace ZeroTier {
@ -36,18 +36,13 @@ namespace ZeroTier {
* *
* MulticastGroup behaves as an immutable value object. * MulticastGroup behaves as an immutable value object.
*/ */
class MulticastGroup class MulticastGroup {
{ public:
public: MulticastGroup() : _mac(), _adi(0)
MulticastGroup() :
_mac(),
_adi(0)
{ {
} }
MulticastGroup(const MAC &m,uint32_t a) : MulticastGroup(const MAC& m, uint32_t a) : _mac(m), _adi(a)
_mac(m),
_adi(a)
{ {
} }
@ -57,21 +52,22 @@ public:
* @param ip IP address (port field is ignored) * @param ip IP address (port field is ignored)
* @return Multicast group for ARP/NDP * @return Multicast group for ARP/NDP
*/ */
static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip) static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress& ip)
{ {
if (ip.isV4()) { if (ip.isV4()) {
// IPv4 wants broadcast MACs, so we shove the V4 address itself into // IPv4 wants broadcast MACs, so we shove the V4 address itself into
// the Multicast Group ADI field. Making V4 ARP work is basically why // the Multicast Group ADI field. Making V4 ARP work is basically why
// ADI was added, as well as handling other things that want mindless // ADI was added, as well as handling other things that want mindless
// Ethernet broadcast to all. // Ethernet broadcast to all.
return MulticastGroup(MAC(0xffffffffffffULL),Utils::ntoh(*((const uint32_t *)ip.rawIpData()))); return MulticastGroup(MAC(0xffffffffffffULL), Utils::ntoh(*((const uint32_t*)ip.rawIpData())));
} else if (ip.isV6()) { }
else if (ip.isV6()) {
// IPv6 is better designed in this respect. We can compute the IPv6 // IPv6 is better designed in this respect. We can compute the IPv6
// multicast address directly from the IP address, and it gives us // multicast address directly from the IP address, and it gives us
// 24 bits of uniqueness. Collisions aren't likely to be common enough // 24 bits of uniqueness. Collisions aren't likely to be common enough
// to care about. // to care about.
const unsigned char *a = (const unsigned char *)ip.rawIpData(); const unsigned char* a = (const unsigned char*)ip.rawIpData();
return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0); return MulticastGroup(MAC(0x33, 0x33, 0xff, a[13], a[14], a[15]), 0);
} }
return MulticastGroup(); return MulticastGroup();
} }
@ -79,35 +75,60 @@ public:
/** /**
* @return Multicast address * @return Multicast address
*/ */
inline const MAC &mac() const { return _mac; } inline const MAC& mac() const
{
return _mac;
}
/** /**
* @return Additional distinguishing information * @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
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
{
return ((_mac != g._mac) || (_adi != g._adi));
}
inline bool operator<(const MulticastGroup& g) const
{ {
if (_mac < g._mac) { if (_mac < g._mac) {
return true; return true;
} else if (_mac == g._mac) { }
else if (_mac == g._mac) {
return (_adi < g._adi); return (_adi < g._adi);
} }
return false; return false;
} }
inline bool operator>(const MulticastGroup &g) const { return (g < *this); } inline bool operator>(const MulticastGroup& g) const
inline bool operator<=(const MulticastGroup &g) const { return !(g < *this); } {
inline bool operator>=(const MulticastGroup &g) const { return !(*this < g); } 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; MAC _mac;
uint32_t _adi; uint32_t _adi;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -14,33 +14,31 @@
#ifndef ZT_NETWORK_HPP #ifndef ZT_NETWORK_HPP
#define ZT_NETWORK_HPP #define ZT_NETWORK_HPP
#include <stdint.h>
#include "../include/ZeroTierOne.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 "Address.hpp"
#include "Mutex.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.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 "CertificateOfMembership.hpp"
#include "Constants.hpp"
#include "Dictionary.hpp"
#include "Hashtable.hpp"
#include "MAC.hpp"
#include "Membership.hpp"
#include "Metrics.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_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 { namespace ZeroTier {
@ -50,11 +48,10 @@ class Peer;
/** /**
* A virtual LAN * A virtual LAN
*/ */
class Network class Network {
{
friend class SharedPtr<Network>; friend class SharedPtr<Network>;
public: public:
/** /**
* Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0 * Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0
*/ */
@ -63,7 +60,10 @@ public:
/** /**
* Compute primary controller device ID from network ID * 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 * Construct a new network
@ -77,18 +77,43 @@ public:
* @param uptr Arbitrary pointer used by externally-facing API (for user use) * @param uptr Arbitrary pointer used by externally-facing API (for user use)
* @param nconf Network config, if known * @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(); ~Network();
inline uint64_t id() const { return _id; } inline uint64_t id() const
inline Address controller() const { return Address(_id >> 24); } {
inline bool multicastEnabled() const { return (_config.multicastLimit > 0); } return _id;
inline bool hasConfig() const { return (_config); } }
inline uint64_t lastConfigUpdate() const { return _lastConfigUpdate; } inline Address controller() const
inline ZT_VirtualNetworkStatus status() const { Mutex::Lock _l(_lock); return _status(); } {
inline const NetworkConfig &config() const { return _config; } return Address(_id >> 24);
inline const MAC &mac() const { return _mac; } }
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 * Apply filters to an outgoing packet
@ -111,17 +136,17 @@ public:
* @return True if packet should be sent, false if dropped or redirected * @return True if packet should be sent, false if dropped or redirected
*/ */
bool filterOutgoingPacket( bool filterOutgoingPacket(
void *tPtr, void* tPtr,
const bool noTee, const bool noTee,
const Address &ztSource, const Address& ztSource,
const Address &ztDest, const Address& ztDest,
const MAC &macSource, const MAC& macSource,
const MAC &macDest, const MAC& macDest,
const uint8_t *frameData, const uint8_t* frameData,
const unsigned int frameLen, const unsigned int frameLen,
const unsigned int etherType, const unsigned int etherType,
const unsigned int vlanId, const unsigned int vlanId,
uint8_t &qosBucket); uint8_t& qosBucket);
/** /**
* Apply filters to an incoming packet * Apply filters to an incoming packet
@ -143,12 +168,12 @@ public:
* @return 0 == drop, 1 == accept, 2 == accept even if bridged * @return 0 == drop, 1 == accept, 2 == accept even if bridged
*/ */
int filterIncomingPacket( int filterIncomingPacket(
void *tPtr, void* tPtr,
const SharedPtr<Peer> &sourcePeer, const SharedPtr<Peer>& sourcePeer,
const Address &ztDest, const Address& ztDest,
const MAC &macSource, const MAC& macSource,
const MAC &macDest, const MAC& macDest,
const uint8_t *frameData, const uint8_t* frameData,
const unsigned int frameLen, const unsigned int frameLen,
const unsigned int etherType, const unsigned int etherType,
const unsigned int vlanId); const unsigned int vlanId);
@ -160,7 +185,7 @@ public:
* @param includeBridgedGroups If true, also check groups we've learned via bridging * @param includeBridgedGroups If true, also check groups we've learned via bridging
* @return True if this network endpoint / peer is a member * @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 * 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 tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param mg New multicast group * @param mg New multicast group
*/ */
void multicastSubscribe(void *tPtr,const MulticastGroup &mg); void multicastSubscribe(void* tPtr, const MulticastGroup& mg);
/** /**
* Unsubscribe from a multicast group * Unsubscribe from a multicast group
* *
* @param mg Multicast group * @param mg Multicast group
*/ */
void multicastUnsubscribe(const MulticastGroup &mg); void multicastUnsubscribe(const MulticastGroup& mg);
/** /**
* Handle an inbound network config chunk * Handle an inbound network config chunk
@ -191,7 +216,7 @@ public:
* @param ptr Index of chunk and related fields in packet * @param ptr Index of chunk and related fields in packet
* @return Update ID if update was fully assembled and accepted or 0 otherwise * @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 * Set network configuration
@ -201,12 +226,12 @@ public:
* @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. * @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 * @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 * 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); Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED;
@ -217,7 +242,7 @@ public:
/** /**
* Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this * 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); Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_NOT_FOUND; _netconfFailure = NETCONF_FAILURE_NOT_FOUND;
@ -228,7 +253,7 @@ public:
/** /**
* Set netconf failure to 'authentication required' possibly with an authorization URL * 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); Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED; _netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED;
@ -242,14 +267,14 @@ public:
* set netconf failure to 'authentication required' along with info needed * set netconf failure to 'authentication required' along with info needed
* for sso full flow authentication. * 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 * 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 * @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 * 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 tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param peer Peer to check * @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 * Check whether a given peer has recently had an association with this network
@ -270,7 +295,7 @@ public:
* @param addr Peer address * @param addr Peer address
* @return True if peer has recently associated * @return True if peer has recently associated
*/ */
bool recentlyAssociatedWith(const Address &addr); bool recentlyAssociatedWith(const Address& addr);
/** /**
* Do periodic cleanup and housekeeping tasks * 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 * @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); Mutex::Lock _l(_lock);
_sendUpdatesToMembers(tPtr,(const MulticastGroup *)0); _sendUpdatesToMembers(tPtr, (const MulticastGroup*)0);
} }
/** /**
@ -294,17 +319,20 @@ public:
* @param mac MAC address * @param mac MAC address
* @return ZeroTier address of bridge to this MAC * @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); Mutex::Lock _l(_lock);
const Address *const br = _remoteBridgeRoutes.get(mac); const Address* const br = _remoteBridgeRoutes.get(mac);
return ((br) ? *br : Address()); return ((br) ? *br : Address());
} }
/** /**
* @return True if QoS is in effect for this network * @return True if QoS is in effect for this network
*/ */
inline bool qosEnabled() { return false; } inline bool qosEnabled()
{
return false;
}
/** /**
* Set a bridge route * Set a bridge route
@ -312,7 +340,7 @@ public:
* @param mac MAC address of destination * @param mac MAC address of destination
* @param addr Bridge this MAC is reachable behind * @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 * Learn a multicast group that is bridged to our tap device
@ -321,52 +349,52 @@ public:
* @param mg Multicast group * @param mg Multicast group
* @param now Current time * @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 * 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 * 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) { if (cap.networkId() != _id) {
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
Mutex::Lock _l(_lock); 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 * 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) { if (tag.networkId() != _id) {
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
Mutex::Lock _l(_lock); 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 * 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 * 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) { if (coo.networkId() != _id) {
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
Mutex::Lock _l(_lock); 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 to Destination peer address
* @param now Current time * @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); Mutex::Lock _l(_lock);
Membership &m = _membership(to); Membership& m = _membership(to);
const int64_t lastPushed = m.lastPushedCredentials(); const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT)) { if ((lastPushed < _lastConfigUpdate) || ((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT)) {
m.pushCredentials(RR,tPtr,now,to,_config); m.pushCredentials(RR, tPtr, now, to, _config);
} }
} }
@ -393,13 +421,13 @@ public:
* @param to Destination peer address * @param to Destination peer address
* @param now Current time * @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); Mutex::Lock _l(_lock);
Membership &m = _membership(to); Membership& m = _membership(to);
const int64_t lastPushed = m.lastPushedCredentials(); const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT)) { if ((lastPushed < _lastConfigUpdate) || ((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT)) {
m.pushCredentials(RR,tPtr,now,to,_config); m.pushCredentials(RR, tPtr, now, to, _config);
} }
} }
@ -416,7 +444,7 @@ public:
* *
* @param ec Buffer to fill with externally-visible network configuration * @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); Mutex::Lock _l(_lock);
_externalConfig(ec); _externalConfig(ec);
@ -425,36 +453,41 @@ public:
/** /**
* @return Externally usable pointer-to-pointer exported via the core API * @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; ZT_VirtualNetworkStatus _status() const;
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked void _externalConfig(ZT_VirtualNetworkConfig* ec) const; // assumes _lock is locked
bool _gate(const SharedPtr<Peer> &peer); bool _gate(const SharedPtr<Peer>& peer);
void _sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup); void _sendUpdatesToMembers(void* tPtr, const MulticastGroup* const newMulticastGroup);
void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups); void _announceMulticastGroupsTo(void* tPtr, const Address& peer, const std::vector<MulticastGroup>& allMulticastGroups);
std::vector<MulticastGroup> _allMulticastGroups() const; std::vector<MulticastGroup> _allMulticastGroups() const;
Membership &_membership(const Address &a); Membership& _membership(const Address& a);
void _sendUpdateEvent(void *tPtr); void _sendUpdateEvent(void* tPtr);
const RuntimeEnvironment *const RR; const RuntimeEnvironment* const RR;
void *_uPtr; void* _uPtr;
const uint64_t _id; const uint64_t _id;
std::string _nwidStr; std::string _nwidStr;
uint64_t _lastAnnouncedMulticastGroupsUpstream; uint64_t _lastAnnouncedMulticastGroupsUpstream;
MAC _mac; // local MAC address MAC _mac; // local MAC address
bool _portInitialized; bool _portInitialized;
std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to (according to tap) 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<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) Hashtable<MAC, Address> _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
NetworkConfig _config; NetworkConfig _config;
int64_t _lastConfigUpdate; int64_t _lastConfigUpdate;
struct _IncomingConfigChunk struct _IncomingConfigChunk {
{ _IncomingConfigChunk()
_IncomingConfigChunk() { memset(this,0,sizeof(_IncomingConfigChunk)); } {
memset(this, 0, sizeof(_IncomingConfigChunk));
}
uint64_t ts; uint64_t ts;
uint64_t updateId; uint64_t updateId;
uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS]; uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS];
@ -466,17 +499,11 @@ private:
bool _destroyed; bool _destroyed;
enum { enum { NETCONF_FAILURE_NONE, NETCONF_FAILURE_ACCESS_DENIED, NETCONF_FAILURE_NOT_FOUND, NETCONF_FAILURE_INIT_FAILED, NETCONF_FAILURE_AUTHENTICATION_REQUIRED } _netconfFailure;
NETCONF_FAILURE_NONE, int _portError; // return value from port config callback
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; std::string _authenticationURL;
Hashtable<Address,Membership> _memberships; Hashtable<Address, Membership> _memberships;
Mutex _lock; Mutex _lock;

View file

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

View file

@ -14,31 +14,29 @@
#ifndef ZT_NETWORKCONFIG_HPP #ifndef ZT_NETWORKCONFIG_HPP
#define 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 "../include/ZeroTierOne.h"
#include "Constants.hpp"
#include "Buffer.hpp"
#include "DNS.hpp"
#include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Buffer.hpp"
#include "Capability.hpp"
#include "CertificateOfMembership.hpp" #include "CertificateOfMembership.hpp"
#include "CertificateOfOwnership.hpp" #include "CertificateOfOwnership.hpp"
#include "Capability.hpp" #include "Constants.hpp"
#include "Tag.hpp" #include "DNS.hpp"
#include "Dictionary.hpp" #include "Dictionary.hpp"
#include "Hashtable.hpp" #include "Hashtable.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Utils.hpp" #include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#include "Tag.hpp"
#include "Trace.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 * Default time delta for COMs, tags, and capabilities
@ -93,7 +91,9 @@
namespace ZeroTier { namespace ZeroTier {
// Dictionary capacity needed for max size network config // 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 // Dictionary capacity needed for max size network meta-data
#define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 1024 #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 * This is a memcpy()'able structure and is safe (in a crash sense) to modify
* without locks. * without locks.
*/ */
class NetworkConfig class NetworkConfig {
{ public:
public: NetworkConfig()
NetworkConfig() : : networkId(0)
networkId(0), , timestamp(0)
timestamp(0), , credentialTimeMaxDelta(0)
credentialTimeMaxDelta(0), , revision(0)
revision(0), , issuedTo()
issuedTo(), , remoteTraceTarget()
remoteTraceTarget(), , flags(0)
flags(0), , remoteTraceLevel(Trace::LEVEL_NORMAL)
remoteTraceLevel(Trace::LEVEL_NORMAL), , mtu(0)
mtu(0), , multicastLimit(0)
multicastLimit(0), , specialistCount(0)
specialistCount(0), , routeCount(0)
routeCount(0), , staticIpCount(0)
staticIpCount(0), , ruleCount(0)
ruleCount(0), , capabilityCount(0)
capabilityCount(0), , tagCount(0)
tagCount(0), , certificateOfOwnershipCount(0)
certificateOfOwnershipCount(0), , capabilities()
capabilities(), , tags()
tags(), , certificatesOfOwnership()
certificatesOfOwnership(), , type(ZT_NETWORK_TYPE_PRIVATE)
type(ZT_NETWORK_TYPE_PRIVATE), , dnsCount(0)
dnsCount(0), , ssoEnabled(false)
ssoEnabled(false), , authenticationURL()
authenticationURL(), , authenticationExpiryTime(0)
authenticationExpiryTime(0), , issuerURL()
issuerURL(), , centralAuthURL()
centralAuthURL(), , ssoNonce()
ssoNonce(), , ssoState()
ssoState(), , ssoClientID()
ssoClientID()
{ {
name[0] = 0; name[0] = 0;
memset(specialists, 0, sizeof(uint64_t)*ZT_MAX_NETWORK_SPECIALISTS); memset(specialists, 0, sizeof(uint64_t) * ZT_MAX_NETWORK_SPECIALISTS);
memset(routes, 0, sizeof(ZT_VirtualNetworkRoute)*ZT_MAX_NETWORK_ROUTES); memset(routes, 0, sizeof(ZT_VirtualNetworkRoute) * ZT_MAX_NETWORK_ROUTES);
memset(staticIps, 0, sizeof(InetAddress)*ZT_MAX_ZT_ASSIGNED_ADDRESSES); memset(staticIps, 0, sizeof(InetAddress) * ZT_MAX_ZT_ASSIGNED_ADDRESSES);
memset(rules, 0, sizeof(ZT_VirtualNetworkRule)*ZT_MAX_NETWORK_RULES); memset(rules, 0, sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES);
memset(&dns, 0, sizeof(ZT_VirtualNetworkDNS)); memset(&dns, 0, sizeof(ZT_VirtualNetworkDNS));
memset(authenticationURL, 0, sizeof(authenticationURL)); memset(authenticationURL, 0, sizeof(authenticationURL));
memset(issuerURL, 0, sizeof(issuerURL)); memset(issuerURL, 0, sizeof(issuerURL));
@ -305,7 +304,7 @@ public:
* @param includeLegacy If true, include legacy fields for old node versions * @param includeLegacy If true, include legacy fields for old node versions
* @return True if dictionary was successfully created, false if e.g. overflow * @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 * 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) * @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 * @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 * @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 * @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 * @return True if frames should not be compressed
@ -344,12 +349,18 @@ public:
/** /**
* @return Network type is public (no access control) * @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) * @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 * @return ZeroTier addresses of devices on this network designated as active bridges
@ -357,7 +368,7 @@ public:
inline std::vector<Address> activeBridges() const inline std::vector<Address> activeBridges() const
{ {
std::vector<Address> r; 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) { if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
r.push_back(Address(specialists[i])); r.push_back(Address(specialists[i]));
} }
@ -368,7 +379,7 @@ public:
inline unsigned int activeBridges(Address ab[ZT_MAX_NETWORK_SPECIALISTS]) const inline unsigned int activeBridges(Address ab[ZT_MAX_NETWORK_SPECIALISTS]) const
{ {
unsigned int c = 0; 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) { if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
ab[c++] = specialists[i]; ab[c++] = specialists[i];
} }
@ -376,10 +387,10 @@ public:
return c; return c;
} }
inline bool isActiveBridge(const Address &a) const inline bool isActiveBridge(const Address& 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_ACTIVE_BRIDGE) != 0)&&(a == specialists[i])) { if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) && (a == specialists[i])) {
return true; return true;
} }
} }
@ -389,7 +400,7 @@ public:
inline std::vector<Address> anchors() const inline std::vector<Address> anchors() const
{ {
std::vector<Address> r; 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) { if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0) {
r.push_back(Address(specialists[i])); r.push_back(Address(specialists[i]));
} }
@ -400,7 +411,7 @@ public:
inline std::vector<Address> multicastReplicators() const inline std::vector<Address> multicastReplicators() const
{ {
std::vector<Address> r; 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) { if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) {
r.push_back(Address(specialists[i])); r.push_back(Address(specialists[i]));
} }
@ -411,7 +422,7 @@ public:
inline unsigned int multicastReplicators(Address mr[ZT_MAX_NETWORK_SPECIALISTS]) const inline unsigned int multicastReplicators(Address mr[ZT_MAX_NETWORK_SPECIALISTS]) const
{ {
unsigned int c = 0; 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) { if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) {
mr[c++] = specialists[i]; mr[c++] = specialists[i];
} }
@ -419,10 +430,10 @@ public:
return c; return c;
} }
inline bool isMulticastReplicator(const Address &a) const inline bool isMulticastReplicator(const Address& 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_MULTICAST_REPLICATOR) != 0)&&(a == specialists[i])) { if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) && (a == specialists[i])) {
return true; return true;
} }
} }
@ -432,7 +443,7 @@ public:
inline std::vector<Address> alwaysContactAddresses() const inline std::vector<Address> alwaysContactAddresses() const
{ {
std::vector<Address> r; 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) { if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
r.push_back(Address(specialists[i])); r.push_back(Address(specialists[i]));
} }
@ -443,7 +454,7 @@ public:
inline unsigned int alwaysContactAddresses(Address ac[ZT_MAX_NETWORK_SPECIALISTS]) const inline unsigned int alwaysContactAddresses(Address ac[ZT_MAX_NETWORK_SPECIALISTS]) const
{ {
unsigned int c = 0; 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) { if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
ac[c++] = specialists[i]; ac[c++] = specialists[i];
} }
@ -451,9 +462,9 @@ public:
return c; 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) { if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
a[Address(specialists[i])]; a[Address(specialists[i])];
} }
@ -464,19 +475,28 @@ public:
* @param fromPeer Peer attempting to bridge other Ethernet peers onto network * @param fromPeer Peer attempting to bridge other Ethernet peers onto network
* @return True if this network allows bridging * @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) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((fromPeer == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)) { if ((fromPeer == specialists[i]) && ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)) {
return true; return true;
} }
} }
return false; return false;
} }
inline operator bool() const { return (networkId != 0); } inline operator bool() const
inline bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); } {
inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); } 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 * Add a specialist or mask flags if already present
@ -488,10 +508,10 @@ public:
* @param f Flags (OR of specialist role/type flags) * @param f Flags (OR of specialist role/type flags)
* @return True if successfully masked or added * @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(); 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) { if ((specialists[i] & 0xffffffffffULL) == aint) {
specialists[i] |= f; specialists[i] |= f;
return true; return true;
@ -504,24 +524,24 @@ public:
return false; 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) { if (capabilities[i].id() == id) {
return &(capabilities[i]); 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) { if (tags[i].id() == id) {
return &(tags[i]); return &(tags[i]);
} }
} }
return (Tag *)0; return (Tag*)0;
} }
/** /**
@ -729,6 +749,6 @@ public:
char ssoProvider[64]; char ssoProvider[64];
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

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

File diff suppressed because it is too large Load diff

View file

@ -14,29 +14,26 @@
#ifndef ZT_NODE_HPP #ifndef ZT_NODE_HPP
#define 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 <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <map>
#include <vector> #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 // Bit mask for "expecting reply" hash
#define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255 #define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255
#define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31 #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. * The pointer returned by ZT_Node_new() is an instance of this class.
*/ */
class Node : public NetworkController::Sender class Node : public NetworkController::Sender {
{ public:
public: Node(void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now);
Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now);
virtual ~Node(); virtual ~Node();
// Get rid of alignment warnings on 32-bit Windows and possibly improve performance // Get rid of alignment warnings on 32-bit Windows and possibly improve performance
#ifdef __WINDOWS__ #ifdef __WINDOWS__
void * operator new(size_t i) { return _mm_malloc(i,16); } void* operator new(size_t i)
void operator delete(void* p) { _mm_free(p); } {
return _mm_malloc(i, 16);
}
void operator delete(void* p)
{
_mm_free(p);
}
#endif #endif
// Public API Functions ---------------------------------------------------- // Public API Functions ----------------------------------------------------
ZT_ResultCode processWirePacket( 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);
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( ZT_ResultCode processVirtualNetworkFrame(
void *tptr, void* tptr,
int64_t now, int64_t now,
uint64_t nwid, uint64_t nwid,
uint64_t sourceMac, uint64_t sourceMac,
uint64_t destMac, uint64_t destMac,
unsigned int etherType, unsigned int etherType,
unsigned int vlanId, unsigned int vlanId,
const void *frameData, const void* frameData,
unsigned int frameLength, unsigned int frameLength,
volatile int64_t *nextBackgroundTaskDeadline); volatile int64_t* nextBackgroundTaskDeadline);
ZT_ResultCode processBackgroundTasks(void *tptr,int64_t now,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 join(uint64_t nwid, void* uptr, void* tptr);
ZT_ResultCode leave(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 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 multicastUnsubscribe(uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi);
ZT_ResultCode orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed); ZT_ResultCode orbit(void* tptr, uint64_t moonWorldId, uint64_t moonSeed);
ZT_ResultCode deorbit(void *tptr,uint64_t moonWorldId); ZT_ResultCode deorbit(void* tptr, uint64_t moonWorldId);
uint64_t address() const; uint64_t address() const;
void status(ZT_NodeStatus *status) const; void status(ZT_NodeStatus* status) const;
ZT_PeerList *peers() const; ZT_PeerList* peers() const;
ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const; ZT_VirtualNetworkConfig* networkConfig(uint64_t nwid) const;
ZT_VirtualNetworkList *networks() const; ZT_VirtualNetworkList* networks() const;
void freeQueryResult(void *qr); void freeQueryResult(void* qr);
int addLocalInterfaceAddress(const struct sockaddr_storage *addr); int addLocalInterfaceAddress(const struct sockaddr_storage* addr);
void clearLocalInterfaceAddresses(); void clearLocalInterfaceAddresses();
int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); int sendUserMessage(void* tptr, uint64_t dest, uint64_t typeId, const void* data, unsigned int len);
void setNetconfMaster(void *networkControllerInstance); void setNetconfMaster(void* networkControllerInstance);
// Internal functions ------------------------------------------------------ // Internal functions ------------------------------------------------------
inline int64_t now() const { return _now; } inline int64_t now() const
inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
{ {
return (_cb.wirePacketSendFunction( return _now;
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) inline bool putPacket(void* tPtr, const int64_t localSocket, const InetAddress& addr, const void* data, unsigned int len, unsigned int ttl = 0)
{ {
_cb.virtualNetworkFrameFunction( return (_cb.wirePacketSendFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, localSocket, reinterpret_cast<const struct sockaddr_storage*>(&addr), data, len, ttl) == 0);
reinterpret_cast<ZT_Node *>(this), }
_uPtr,
tPtr, 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)
nwid, {
nuptr, _cb.virtualNetworkFrameFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, nwid, nuptr, source.toInt(), dest.toInt(), etherType, vlanId, data, len);
source.toInt(),
dest.toInt(),
etherType,
vlanId,
data,
len);
} }
inline SharedPtr<Network> network(uint64_t nwid) const inline SharedPtr<Network> network(uint64_t nwid) const
{ {
Mutex::Lock _l(_networks_m); Mutex::Lock _l(_networks_m);
const SharedPtr<Network> *n = _networks.get(nwid); const SharedPtr<Network>* n = _networks.get(nwid);
if (n) { if (n) {
return *n; return *n;
} }
@ -150,14 +129,14 @@ public:
return _networks.contains(nwid); 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); Mutex::Lock _l(_networks_m);
Hashtable< uint64_t,SharedPtr<Network> >::Iterator i(*const_cast< Hashtable< uint64_t,SharedPtr<Network> > * >(&_networks)); Hashtable<uint64_t, SharedPtr<Network> >::Iterator i(*const_cast<Hashtable<uint64_t, SharedPtr<Network> >*>(&_networks));
uint64_t *k = (uint64_t *)0; uint64_t* k = (uint64_t*)0;
SharedPtr<Network> *v = (SharedPtr<Network> *)0; SharedPtr<Network>* v = (SharedPtr<Network>*)0;
while (i.next(k,v)) { while (i.next(k, v)) {
nw.push_back(*v); nw.push_back(*v);
} }
return nw; return nw;
@ -169,30 +148,60 @@ public:
return _directPaths; 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 int stateObjectGet(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2], void* const data, const unsigned int 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); } 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); 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 ); } 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(); 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; World planet() const;
std::vector<World> moons() 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 * 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 uint32_t pid2 = (uint32_t)(packetId >> 32);
const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1); 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) { if (_expectingRepliesTo[bucket][i] == pid2) {
return true; return true;
} }
@ -239,7 +248,7 @@ public:
* @param from Source address of packet * @param from Source address of packet
* @return True if within rate limits * @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(); unsigned long iph = from.rateGateHash();
if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) { if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) {
@ -249,17 +258,23 @@ public:
return false; return false;
} }
virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig); 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 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 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 const Address& remoteTraceTarget() const
inline Trace::Level remoteTraceLevel() const { return _remoteTraceLevel; } {
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(); _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(); _localControllerAuthorizations_m.unlock();
if (at) { if (at) {
return ((now - *at) < (ZT_NETWORK_AUTOCONF_DELAY * 3)); return ((now - *at) < (ZT_NETWORK_AUTOCONF_DELAY * 3));
@ -267,7 +282,7 @@ public:
return false; 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.inVerbCounts[v];
_stats.inVerbBytes[v] += (uint64_t)bytes; _stats.inVerbBytes[v] += (uint64_t)bytes;
@ -285,11 +300,10 @@ public:
void initMultithreading(unsigned int concurrency, bool cpuPinningEnabled); void initMultithreading(unsigned int concurrency, bool cpuPinningEnabled);
public:
public:
RuntimeEnvironment _RR; RuntimeEnvironment _RR;
RuntimeEnvironment *RR; RuntimeEnvironment* RR;
void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P void* _uPtr; // _uptr (lower case) is reserved in Visual Studio :P
ZT_Node_Callbacks _cb; ZT_Node_Callbacks _cb;
// For tracking packet IDs to filter out OK/ERROR replies to packets we did not send // 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 // Map that remembers if we have recently sent a network config to someone
// querying us as a controller. // querying us as a controller.
struct _LocalControllerAuth struct _LocalControllerAuth {
{ uint64_t nwid, address;
uint64_t nwid,address; _LocalControllerAuth(const uint64_t nwid_, const Address& address_) : nwid(nwid_), address(address_.toInt())
_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 unsigned long hashCode() const
inline bool operator!=(const _LocalControllerAuth &a) const { return ((a.nwid != nwid)||(a.address != address)); } {
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; Mutex _localControllerAuthorizations_m;
Hashtable< uint64_t,SharedPtr<Network> > _networks; Hashtable<uint64_t, SharedPtr<Network> > _networks;
Mutex _networks_m; Mutex _networks_m;
std::vector<InetAddress> _directPaths; std::vector<InetAddress> _directPaths;
@ -336,6 +360,6 @@ public:
bool _lowBandwidthMode; bool _lowBandwidthMode;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -11,28 +11,29 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "RuntimeEnvironment.hpp"
#include "OutboundMulticast.hpp" #include "OutboundMulticast.hpp"
#include "Switch.hpp"
#include "Constants.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "Peer.hpp" #include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp" #include "Topology.hpp"
namespace ZeroTier { namespace ZeroTier {
void OutboundMulticast::init( void OutboundMulticast::init(
const RuntimeEnvironment *RR, const RuntimeEnvironment* RR,
uint64_t timestamp, uint64_t timestamp,
uint64_t nwid, uint64_t nwid,
bool disableCompression, bool disableCompression,
unsigned int limit, unsigned int limit,
unsigned int gatherLimit, unsigned int gatherLimit,
const MAC &src, const MAC& src,
const MulticastGroup &dest, const MulticastGroup& dest,
unsigned int etherType, unsigned int etherType,
const void *payload, const void* payload,
unsigned int len) unsigned int len)
{ {
uint8_t flags = 0; uint8_t flags = 0;
@ -42,8 +43,9 @@ void OutboundMulticast::init(
if (src) { if (src) {
_macSrc = src; _macSrc = src;
flags |= 0x04; flags |= 0x04;
} else { }
_macSrc.fromAddress(RR->identity.address(),nwid); else {
_macSrc.fromAddress(RR->identity.address(), nwid);
} }
_macDest = dest.mac(); _macDest = dest.mac();
_limit = limit; _limit = limit;
@ -67,26 +69,26 @@ void OutboundMulticast::init(
dest.mac().appendTo(_packet); dest.mac().appendTo(_packet);
_packet.append((uint32_t)dest.adi()); _packet.append((uint32_t)dest.adi());
_packet.append((uint16_t)etherType); _packet.append((uint16_t)etherType);
_packet.append(payload,_frameLen); _packet.append(payload, _frameLen);
if (!disableCompression) { if (! disableCompression) {
_packet.compress(); _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)); const SharedPtr<Network> nw(RR->node->network(_nwid));
uint8_t QoSBucket = 255; // Dummy value uint8_t QoSBucket = 255; // Dummy value
if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr,_macSrc,_macDest,_frameData,_frameLen,_etherType,0,QoSBucket))) { if ((nw) && (nw->filterOutgoingPacket(tPtr, true, RR->identity.address(), toAddr, _macSrc, _macDest, _frameData, _frameLen, _etherType, 0, QoSBucket))) {
nw->pushCredentialsIfNeeded(tPtr,toAddr,RR->node->now()); nw->pushCredentialsIfNeeded(tPtr, toAddr, RR->node->now());
_packet.newInitializationVector(); _packet.newInitializationVector();
_packet.setDestination(toAddr); _packet.setDestination(toAddr);
RR->node->expectReplyTo(_packet.packetId()); RR->node->expectReplyTo(_packet.packetId());
_tmp = _packet; _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 #ifndef ZT_OUTBOUNDMULTICAST_HPP
#define ZT_OUTBOUNDMULTICAST_HPP #define ZT_OUTBOUNDMULTICAST_HPP
#include <stdint.h> #include "Address.hpp"
#include <vector>
#include <algorithm>
#include "Constants.hpp" #include "Constants.hpp"
#include "MAC.hpp" #include "MAC.hpp"
#include "MulticastGroup.hpp" #include "MulticastGroup.hpp"
#include "Address.hpp"
#include "Packet.hpp" #include "Packet.hpp"
#include <algorithm>
#include <stdint.h>
#include <vector>
namespace ZeroTier { namespace ZeroTier {
class CertificateOfMembership; class CertificateOfMembership;
@ -35,15 +34,16 @@ class RuntimeEnvironment;
* *
* This object isn't guarded by a mutex; caller must synchronize access. * This object isn't guarded by a mutex; caller must synchronize access.
*/ */
class OutboundMulticast class OutboundMulticast {
{ public:
public:
/** /**
* Create an uninitialized outbound multicast * Create an uninitialized outbound multicast
* *
* It must be initialized with init(). * It must be initialized with init().
*/ */
OutboundMulticast() {} OutboundMulticast()
{
}
/** /**
* Initialize outbound multicast * Initialize outbound multicast
@ -62,33 +62,42 @@ public:
* @throws std::out_of_range Data too large to fit in a MULTICAST_FRAME * @throws std::out_of_range Data too large to fit in a MULTICAST_FRAME
*/ */
void init( void init(
const RuntimeEnvironment *RR, const RuntimeEnvironment* RR,
uint64_t timestamp, uint64_t timestamp,
uint64_t nwid, uint64_t nwid,
bool disableCompression, bool disableCompression,
unsigned int limit, unsigned int limit,
unsigned int gatherLimit, unsigned int gatherLimit,
const MAC &src, const MAC& src,
const MulticastGroup &dest, const MulticastGroup& dest,
unsigned int etherType, unsigned int etherType,
const void *payload, const void* payload,
unsigned int len); unsigned int len);
/** /**
* @return Multicast creation time * @return Multicast creation time
*/ */
inline uint64_t timestamp() const { return _timestamp; } inline uint64_t timestamp() const
{
return _timestamp;
}
/** /**
* @param now Current time * @param now Current time
* @return True if this multicast is expired (has exceeded transmit timeout) * @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 * @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 * 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 tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param toAddr Destination address * @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 * 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 tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param toAddr Destination address * @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); _alreadySentTo.push_back(toAddr);
sendOnly(RR,tPtr,toAddr); sendOnly(RR, tPtr, toAddr);
} }
/** /**
@ -117,7 +126,7 @@ public:
* *
* @param toAddr Address to log as sent * @param toAddr Address to log as sent
*/ */
inline void logAsSent(const Address &toAddr) inline void logAsSent(const Address& toAddr)
{ {
_alreadySentTo.push_back(toAddr); _alreadySentTo.push_back(toAddr);
} }
@ -130,17 +139,18 @@ public:
* @param toAddr Destination address * @param toAddr Destination address
* @return True if address is new and packet was sent to switch, false if duplicate * @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()) { if (std::find(_alreadySentTo.begin(), _alreadySentTo.end(), toAddr) == _alreadySentTo.end()) {
sendAndLog(RR,tPtr,toAddr); sendAndLog(RR, tPtr, toAddr);
return true; return true;
} else { }
else {
return false; return false;
} }
} }
private: private:
uint64_t _timestamp; uint64_t _timestamp;
uint64_t _nwid; uint64_t _nwid;
MAC _macSrc; MAC _macSrc;
@ -148,11 +158,11 @@ private:
unsigned int _limit; unsigned int _limit;
unsigned int _frameLen; unsigned int _frameLen;
unsigned int _etherType; unsigned int _etherType;
Packet _packet,_tmp; Packet _packet, _tmp;
std::vector<Address> _alreadySentTo; std::vector<Address> _alreadySentTo;
uint8_t _frameData[ZT_MAX_MTU]; uint8_t _frameData[ZT_MAX_MTU];
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -14,21 +14,19 @@
#ifndef ZT_N_PACKET_HPP #ifndef ZT_N_PACKET_HPP
#define ZT_N_PACKET_HPP #define ZT_N_PACKET_HPP
#include <stdint.h> #include "AES.hpp"
#include <string.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include "Constants.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Poly1305.hpp" #include "Poly1305.hpp"
#include "Salsa20.hpp" #include "Salsa20.hpp"
#include "AES.hpp"
#include "Utils.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 * Protocol version -- incremented only for major changes
@ -221,12 +219,12 @@
#define ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT 0x02 #define ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT 0x02
// Field indexes in packet header // Field indexes in packet header
#define ZT_PACKET_IDX_IV 0 #define ZT_PACKET_IDX_IV 0
#define ZT_PACKET_IDX_DEST 8 #define ZT_PACKET_IDX_DEST 8
#define ZT_PACKET_IDX_SOURCE 13 #define ZT_PACKET_IDX_SOURCE 13
#define ZT_PACKET_IDX_FLAGS 18 #define ZT_PACKET_IDX_FLAGS 18
#define ZT_PACKET_IDX_MAC 19 #define ZT_PACKET_IDX_MAC 19
#define ZT_PACKET_IDX_VERB 27 #define ZT_PACKET_IDX_VERB 27
#define ZT_PACKET_IDX_PAYLOAD 28 #define ZT_PACKET_IDX_PAYLOAD 28
/** /**
@ -240,12 +238,12 @@
#define ZT_PROTO_MIN_PACKET_LENGTH ZT_PACKET_IDX_PAYLOAD #define ZT_PROTO_MIN_PACKET_LENGTH ZT_PACKET_IDX_PAYLOAD
// Indexes of fields in fragment header // Indexes of fields in fragment header
#define ZT_PACKET_FRAGMENT_IDX_PACKET_ID 0 #define ZT_PACKET_FRAGMENT_IDX_PACKET_ID 0
#define ZT_PACKET_FRAGMENT_IDX_DEST 8 #define ZT_PACKET_FRAGMENT_IDX_DEST 8
#define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR 13 #define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR 13
#define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO 14 #define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO 14
#define ZT_PACKET_FRAGMENT_IDX_HOPS 15 #define ZT_PACKET_FRAGMENT_IDX_HOPS 15
#define ZT_PACKET_FRAGMENT_IDX_PAYLOAD 16 #define ZT_PACKET_FRAGMENT_IDX_PAYLOAD 16
/** /**
* Magic number found at ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR * Magic number found at ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR
@ -264,89 +262,89 @@
// See their respective handler functions. // See their respective handler functions.
#define ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION (ZT_PACKET_IDX_PAYLOAD) #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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID 8 #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_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_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_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_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_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_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_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_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_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_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_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_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 (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_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_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_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_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_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 // 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 (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_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_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_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_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_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_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_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_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) #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 * 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. * sent in the clear, as it's the "here is my public key" message.
*/ */
class Packet : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH> class Packet : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH> {
{ public:
public:
/** /**
* A packet fragment * A packet fragment
* *
@ -417,22 +414,17 @@ public:
* receipt to authenticate and decrypt; there is no per-fragment MAC. (But if * 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.) * fragments are corrupt, the MAC will fail for the whole assembled packet.)
*/ */
class Fragment : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH> class Fragment : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH> {
{ public:
public: Fragment() : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>()
Fragment() :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>()
{ {
} }
template<unsigned int C2> template <unsigned int C2> Fragment(const Buffer<C2>& b) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
Fragment(const Buffer<C2> &b) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
{ {
} }
Fragment(const void *data,unsigned int len) : Fragment(const void* data, unsigned int len) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data, 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 fragNo Which fragment (>= 1, since 0 is Packet with end chopped off)
* @param fragTotal Total number of fragments (including 0) * @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 fragNo Which fragment (>= 1, since 0 is Packet with end chopped off)
* @param fragTotal Total number of fragments (including 0) * @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()) { if ((fragStart + fragLen) > p.size()) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
@ -467,13 +459,13 @@ public:
setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH); setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH);
// NOTE: this copies both the IV/packet ID and the destination address. // 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_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR;
(*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf)); (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf));
(*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0; (*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 * @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 * @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 * @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 * @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 * @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 * @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 * Increment this packet's hop count
@ -519,14 +529,17 @@ public:
/** /**
* @return Length of payload in bytes * @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 * @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: * ERROR response payload:
* <[8] 64-bit network ID> * <[8] 64-bit network ID>
* <[2] 16-bit length of error-related data (optional)> * <[2] 16-bit length of error-related data (optional)>
* <[...] error-related data (optional)> * <[...] error-related data (optional)>
* *
* Error related data is a Dictionary containing things like a URL * Error related data is a Dictionary containing things like a URL
* for authentication or a human-readable error message, and is * for authentication or a human-readable error message, and is
* optional and may be absent or empty. * optional and may be absent or empty.
*/ */
VERB_NETWORK_CONFIG_REQUEST = 0x0b, VERB_NETWORK_CONFIG_REQUEST = 0x0b,
@ -1056,8 +1069,7 @@ public:
/** /**
* Error codes for VERB_ERROR * Error codes for VERB_ERROR
*/ */
enum ErrorCode enum ErrorCode {
{
/* No error, not actually used in transit */ /* No error, not actually used in transit */
ERROR_NONE = 0x00, ERROR_NONE = 0x00,
@ -1085,18 +1097,15 @@ public:
/* Multicasts to this group are not wanted */ /* Multicasts to this group are not wanted */
ERROR_UNWANTED_MULTICAST = 0x08, ERROR_UNWANTED_MULTICAST = 0x08,
/* Network requires external or 2FA authentication (e.g. SSO). */ /* Network requires external or 2FA authentication (e.g. SSO). */
ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09 ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09
}; };
template<unsigned int C2> template <unsigned int C2> Packet(const Buffer<C2>& b) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
Packet(const Buffer<C2> &b) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
{ {
} }
Packet(const void *data,unsigned int len) : Packet(const void* data, unsigned int len) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data, 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 * Use the header access methods (setDestination() and friends) to fill out
* the header. Payload should be appended; initial size is header size. * the header. Payload should be appended; initial size is header size.
*/ */
Packet() : Packet() : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
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);
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops
} }
/** /**
@ -1123,10 +1131,9 @@ public:
* @param prototype Prototype packet * @param prototype Prototype packet
* @param dest Destination ZeroTier address for new packet * @param dest Destination ZeroTier address for new packet
*/ */
Packet(const Packet &prototype,const Address &dest) : Packet(const Packet& prototype, const Address& dest) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(prototype)
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); setDestination(dest);
} }
@ -1137,13 +1144,12 @@ public:
* @param source Source ZT address * @param source Source ZT address
* @param v Verb * @param v Verb
*/ */
Packet(const Address &dest,const Address &source,const Verb v) : Packet(const Address& dest, const Address& source, const Verb v) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
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); setDestination(dest);
setSource(source); setSource(source);
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
setVerb(v); setVerb(v);
} }
@ -1154,13 +1160,13 @@ public:
* @param source Source ZT address * @param source Source ZT address
* @param v Verb * @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); 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); setDestination(dest);
setSource(source); 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); setVerb(v);
} }
@ -1171,45 +1177,66 @@ public:
* technically different but otherwise identical copies of the same * technically different but otherwise identical copies of the same
* packet. * 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 * Set this packet's destination
* *
* @param dest ZeroTier address of 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 * Set this packet's source
* *
* @param source ZeroTier address of 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 * Get this packet's destination
* *
* @return Destination ZT address * @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 * Get this packet's source
* *
* @return Source ZT address * @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 * @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) * @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 * Set this packet's fragmented flag
@ -1220,7 +1247,8 @@ public:
{ {
if (f) { if (f) {
(*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED; (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED;
} else { }
else {
(*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED); (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED);
} }
} }
@ -1228,19 +1256,25 @@ public:
/** /**
* @return True if compressed (result only valid if unencrypted) * @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) * @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 * Increment this packet's hop count
*/ */
inline void incrementHops() 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); b = (b & 0xf8) | ((b + 1) & 0x07);
} }
@ -1265,12 +1299,13 @@ public:
*/ */
inline void setCipher(unsigned int c) inline void setCipher(unsigned int c)
{ {
unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; unsigned char& b = (*this)[ZT_PACKET_IDX_FLAGS];
b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH
// Set DEPRECATED "encrypted" flag -- used by pre-1.0.3 peers // Set DEPRECATED "encrypted" flag -- used by pre-1.0.3 peers
if (c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) { if (c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) {
b |= ZT_PROTO_FLAG_ENCRYPTED; b |= ZT_PROTO_FLAG_ENCRYPTED;
} else { }
else {
b &= (~ZT_PROTO_FLAG_ENCRYPTED); b &= (~ZT_PROTO_FLAG_ENCRYPTED);
} }
} }
@ -1280,7 +1315,10 @@ public:
* *
* @return Trusted path ID (from MAC field) * @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 * 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) inline void setTrusted(const uint64_t tpid)
{ {
setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH); 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 * @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 * Set packet verb
@ -1314,22 +1355,34 @@ public:
* *
* @param v New packet verb * @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) * @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 * @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 * @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 * Armor packet for transport
@ -1338,7 +1391,7 @@ public:
* @param encryptPayload If true, encrypt packet payload, else just MAC * @param encryptPayload If true, encrypt packet payload, else just MAC
* @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV * @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 * 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 * @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 * @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 * Encrypt/decrypt a separately armored portion of a packet
@ -1366,7 +1419,7 @@ public:
* @param start Start of encrypted portion * @param start Start of encrypted portion
* @param len Length 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) * Attempt to compress payload if not already (must be unencrypted)
@ -1390,7 +1443,7 @@ public:
*/ */
bool uncompress(); bool uncompress();
private: private:
static const unsigned char ZERO_KEY[32]; static const unsigned char ZERO_KEY[32];
/** /**
@ -1404,13 +1457,13 @@ private:
* @param in Input key (32 bytes) * @param in Input key (32 bytes)
* @param out Output buffer (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 // IV and source/destination addresses. Using the addresses divides the
// key space into two halves-- A->B and B->A (since order will change). // 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]; out[i] = in[i] ^ d[i];
} }
@ -1422,15 +1475,15 @@ private:
// Raw packet size in bytes -- thus each packet size defines a new // Raw packet size in bytes -- thus each packet size defines a new
// key space. // key space.
out[19] = in[19] ^ (unsigned char)(size() & 0xff); 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 // 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]; out[i] = in[i];
} }
} }
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -13,9 +13,9 @@
#include "PacketMultiplexer.hpp" #include "PacketMultiplexer.hpp"
#include "Constants.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp" #include "RuntimeEnvironment.hpp"
#include "Constants.hpp"
#include <stdio.h> #include <stdio.h>
#include <stdlib.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) 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__) #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; return;
#endif #endif
if (!_enabled) { if (! _enabled) {
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; return;
} }

View file

@ -12,18 +12,19 @@
/****/ /****/
#include "Path.hpp" #include "Path.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp"
namespace ZeroTier { 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; _lastOut = now;
return true; return true;
} }
return false; return false;
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,20 +14,19 @@
#ifndef ZT_PATH_HPP #ifndef ZT_PATH_HPP
#define ZT_PATH_HPP #define ZT_PATH_HPP
#include <stdint.h> #include "AtomicCounter.hpp"
#include <string.h>
#include <stdlib.h>
#include <stdexcept>
#include <algorithm>
#include "Constants.hpp" #include "Constants.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
#include "Utils.hpp"
#include "Packet.hpp" #include "Packet.hpp"
#include "RingBuffer.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() * Maximum return value of preferenceRank()
@ -41,89 +40,102 @@ class RuntimeEnvironment;
/** /**
* A path across the physical network * A path across the physical network
*/ */
class Path class Path {
{
friend class SharedPtr<Path>; friend class SharedPtr<Path>;
friend class Bond; friend class Bond;
public: public:
/** /**
* Efficient unique key for paths in a Hashtable * Efficient unique key for paths in a Hashtable
*/ */
class HashKey class HashKey {
{ public:
public: HashKey()
HashKey() {} {
}
HashKey(const int64_t l,const InetAddress &r) HashKey(const int64_t l, const InetAddress& r)
{ {
if (r.ss_family == AF_INET) { if (r.ss_family == AF_INET) {
_k[0] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_addr.s_addr; _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[1] = (uint64_t)reinterpret_cast<const struct sockaddr_in*>(&r)->sin_port;
_k[2] = (uint64_t)l; _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); else if (r.ss_family == AF_INET6) {
_k[2] = ((uint64_t)reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port << 32) ^ (uint64_t)l; memcpy(_k, reinterpret_cast<const struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, 16);
} else { _k[2] = ((uint64_t)reinterpret_cast<const struct sockaddr_in6*>(&r)->sin6_port << 32) ^ (uint64_t)l;
memcpy(_k,&r,std::min(sizeof(_k),sizeof(InetAddress))); }
else {
memcpy(_k, &r, std::min(sizeof(_k), sizeof(InetAddress)));
_k[2] += (uint64_t)l; _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
inline bool operator!=(const HashKey &k) const { return (!(*this == k)); } {
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]; uint64_t _k[3];
}; };
Path() : Path()
_lastOut(0), : _lastOut(0)
_lastIn(0), , _lastIn(0)
_lastTrustEstablishedPacketReceived(0), , _lastTrustEstablishedPacketReceived(0)
_lastEchoRequestReceived(0), , _lastEchoRequestReceived(0)
_localPort(0), , _localPort(0)
_localSocket(-1), , _localSocket(-1)
_latencyMean(0.0), , _latencyMean(0.0)
_latencyVariance(0.0), , _latencyVariance(0.0)
_packetLossRatio(0.0), , _packetLossRatio(0.0)
_packetErrorRatio(0.0), , _packetErrorRatio(0.0)
_assignedFlowCount(0), , _assignedFlowCount(0)
_valid(true), , _valid(true)
_eligible(false), , _eligible(false)
_bonded(false), , _bonded(false)
_mtu(0), , _mtu(0)
_givenLinkSpeed(0), , _givenLinkSpeed(0)
_relativeQuality(0), , _relativeQuality(0)
_latency(0xffff), , _latency(0xffff)
_addr(), , _addr()
_ipScope(InetAddress::IP_SCOPE_NONE) , _ipScope(InetAddress::IP_SCOPE_NONE)
{} {
}
Path(const int64_t localSocket,const InetAddress &addr) : Path(const int64_t localSocket, const InetAddress& addr)
_lastOut(0), : _lastOut(0)
_lastIn(0), , _lastIn(0)
_lastTrustEstablishedPacketReceived(0), , _lastTrustEstablishedPacketReceived(0)
_lastEchoRequestReceived(0), , _lastEchoRequestReceived(0)
_localPort(0), , _localPort(0)
_localSocket(localSocket), , _localSocket(localSocket)
_latencyMean(0.0), , _latencyMean(0.0)
_latencyVariance(0.0), , _latencyVariance(0.0)
_packetLossRatio(0.0), , _packetLossRatio(0.0)
_packetErrorRatio(0.0), , _packetErrorRatio(0.0)
_assignedFlowCount(0), , _assignedFlowCount(0)
_valid(true), , _valid(true)
_eligible(false), , _eligible(false)
_bonded(false), , _bonded(false)
_mtu(0), , _mtu(0)
_givenLinkSpeed(0), , _givenLinkSpeed(0)
_relativeQuality(0), , _relativeQuality(0)
_latency(0xffff), , _latency(0xffff)
_addr(addr), , _addr(addr)
_ipScope(addr.ipScope()) , _ipScope(addr.ipScope())
{} {
}
/** /**
* Called when a packet is received from this remote path, regardless of content * 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()) * 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) * Send a packet via this path (last out time is also updated)
@ -150,14 +165,17 @@ public:
* @param now Current time * @param now Current time
* @return True if transport reported success * @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 * Manually update last sent time
* *
* @param t Time of send * @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 * Update path latency with a new measurement
@ -169,7 +187,8 @@ public:
unsigned int pl = _latency; unsigned int pl = _latency;
if (pl < 0xffff) { if (pl < 0xffff) {
_latency = (pl + l) / 2; _latency = (pl + l) / 2;
} else { }
else {
_latency = l; _latency = l;
} }
} }
@ -177,27 +196,42 @@ public:
/** /**
* @return Local socket as specified by external code * @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 * @return Local port corresponding to the localSocket
*/ */
inline int64_t localPort() const { return _localPort; } inline int64_t localPort() const
{
return _localPort;
}
/** /**
* @return Physical address * @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() * @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 * @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 * @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 // 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. // 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 * @param a Address to check
* @return True if address is good for ZeroTier path use * @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)) { if ((a.ss_family == AF_INET) || (a.ss_family == AF_INET6)) {
switch(a.ipScope()) { switch (a.ipScope()) {
/* Note: we don't do link-local at the moment. Unfortunately these /* Note: we don't do link-local at the moment. Unfortunately these
* cause several issues. The first is that they usually require a * cause several issues. The first is that they usually require a
* device qualifier, which we don't handle yet and can't portably * 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 // TEMPORARY HACK: for now, we are going to blacklist he.net IPv6
// tunnels due to very spotty performance and low MTU issues over // tunnels due to very spotty performance and low MTU issues over
// these IPv6 tunnel links. // these IPv6 tunnel links.
const uint8_t *ipd = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr); 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)) { if ((ipd[0] == 0x20) && (ipd[1] == 0x01) && (ipd[2] == 0x04) && (ipd[3] == 0x70)) {
return false; return false;
} }
} }
@ -253,7 +287,10 @@ public:
/** /**
* @return Latency or 0xffff if unknown * @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 * @return Path quality -- lower is better
@ -261,41 +298,57 @@ public:
inline long quality(const int64_t now) const inline long quality(const int64_t now) const
{ {
const int l = (long)_latency; 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 (((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) * @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 (now - _lastIn) < (ZT_PATH_HEARTBEAT_PERIOD + 5000);
} }
/** /**
* @return True if this path needs a heartbeat * @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 * @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 * @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 * @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 * @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 * Rate limit gate for inbound ECHO requests
@ -312,69 +365,102 @@ public:
/** /**
* @return Mean latency as reported by the bonding layer * @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 * @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 * @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 * @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 * @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 * @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 * 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 * @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 * @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) * @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 * @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 * @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 * @return Physical interface name that this path lives on
*/ */
char *ifname() { char* ifname()
{
return _ifname; return _ifname;
} }
private: private:
char _ifname[ZT_MAX_PHYSIFNAME] = {};
char _ifname[ZT_MAX_PHYSIFNAME] = { };
volatile int64_t _lastOut; volatile int64_t _lastOut;
volatile int64_t _lastIn; volatile int64_t _lastIn;
@ -399,10 +485,10 @@ private:
volatile unsigned int _latency; volatile unsigned int _latency;
InetAddress _addr; 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; AtomicCounter __refCount;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -11,24 +11,25 @@
*/ */
/****/ /****/
#include "Peer.hpp"
#include "../version.h" #include "../version.h"
#include "Constants.hpp" #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 "InetAddress.hpp"
#include "RingBuffer.hpp"
#include "Utils.hpp"
#include "Metrics.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 { namespace ZeroTier {
static unsigned char s_freeRandomByteCounter = 0; 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) : RR(renv)
, _lastReceive(0) , _lastReceive(0)
, _lastNontrivialReceive(0) , _lastNontrivialReceive(0)
@ -52,29 +53,29 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
, _localMultipathSupported(false) , _localMultipathSupported(false)
, _lastComputedAggregateMeanLatency(0) , _lastComputedAggregateMeanLatency(0)
#ifndef ZT_NO_PEER_METRICS #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})} , _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"}})} , _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"}})} , _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())}})} , _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())}})} , _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())}})} , _packet_errors { Metrics::peer_packet_errors.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }) }
#endif #endif
{ {
if (!myIdentity.agree(peerIdentity,_key)) { if (! myIdentity.agree(peerIdentity, _key)) {
throw ZT_EXCEPTION_INVALID_ARGUMENT; throw ZT_EXCEPTION_INVALID_ARGUMENT;
} }
uint8_t ktmp[ZT_SYMMETRIC_KEY_SIZE]; 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); _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); _aesKeys[1].init(ktmp);
Utils::burn(ktmp,ZT_SYMMETRIC_KEY_SIZE); Utils::burn(ktmp, ZT_SYMMETRIC_KEY_SIZE);
} }
void Peer::received( void Peer::received(
void *tPtr, void* tPtr,
const SharedPtr<Path> &path, const SharedPtr<Path>& path,
const unsigned int hops, const unsigned int hops,
const uint64_t packetId, const uint64_t packetId,
const unsigned int payloadLength, const unsigned int payloadLength,
@ -114,7 +115,7 @@ void Peer::received(
bool havePath = false; bool havePath = false;
{ {
Mutex::Lock _l(_paths_m); 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) {
if (_paths[i].p == path) { if (_paths[i].p == path) {
_paths[i].lr = now; _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 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->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; havePath = true;
break; break;
} }
} }
} else { }
else {
break; 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) { if (verb == Packet::VERB_OK) {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
unsigned int oldestPathIdx = ZT_MAX_PEER_NETWORK_PATHS; unsigned int oldestPathIdx = ZT_MAX_PEER_NETWORK_PATHS;
unsigned int oldestPathAge = 0; unsigned int oldestPathAge = 0;
unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS; 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) { if (_paths[i].p) {
// Keep track of oldest path as a last resort option // Keep track of oldest path as a last resort option
unsigned int currAge = _paths[i].p->age(now); 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->address().ipsEqual(path->address())) {
if (_paths[i].p->localSocket() == path->localSocket()) { if (_paths[i].p->localSocket() == path->localSocket()) {
if (!_paths[i].p->alive(now)) { if (! _paths[i].p->alive(now)) {
replacePath = i; replacePath = i;
break; break;
} }
} }
} }
} else { }
else {
replacePath = i; replacePath = i;
break; break;
} }
@ -171,30 +174,33 @@ void Peer::received(
_paths[replacePath].p = path; _paths[replacePath].p = path;
_paths[replacePath].priority = 1; _paths[replacePath].priority = 1;
Mutex::Lock _l(_bond_m); Mutex::Lock _l(_bond_m);
if(_bond) { if (_bond) {
_bond->nominatePathToBond(_paths[replacePath].p, now); _bond->nominatePathToBond(_paths[replacePath].p, now);
} }
} }
} else { }
else {
Mutex::Lock ltl(_lastTriedPath_m); Mutex::Lock ltl(_lastTriedPath_m);
bool triedTooRecently = false; 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) { if ((now - i->second) > 1000) {
_lastTriedPath.erase(i++); _lastTriedPath.erase(i++);
} else if (i->first == path.ptr()) { }
else if (i->first == path.ptr()) {
++i; ++i;
triedTooRecently = true; triedTooRecently = true;
} else { }
else {
++i; ++i;
} }
} }
if (!triedTooRecently) { if (! triedTooRecently) {
_lastTriedPath.push_back(std::pair< Path *, int64_t >(path.ptr(), now)); _lastTriedPath.push_back(std::pair<Path*, int64_t>(path.ptr(), now));
attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true); attemptToContactAt(tPtr, path->localSocket(), path->address(), now, true);
path->sent(now); 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> pathsToPush(RR->node->directPaths());
std::vector<InetAddress> ma = RR->sa->whoami(); std::vector<InetAddress> ma = RR->sa->whoami();
pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end()); pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end());
if (!pathsToPush.empty()) { if (! pathsToPush.empty()) {
std::vector<InetAddress>::const_iterator p(pathsToPush.begin()); std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
while (p != pathsToPush.end()) { while (p != pathsToPush.end()) {
Packet *const outp = new Packet(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); Packet* const outp = new Packet(_id.address(), RR->identity.address(), Packet::VERB_PUSH_DIRECT_PATHS);
outp->addSize(2); // leave room for count outp->addSize(2); // leave room for count
unsigned int count = 0; unsigned int count = 0;
while ((p != pathsToPush.end())&&((outp->size() + 24) < 1200)) { while ((p != pathsToPush.end()) && ((outp->size() + 24) < 1200)) {
uint8_t addressType = 4; uint8_t addressType = 4;
switch(p->ss_family) { switch (p->ss_family) {
case AF_INET: case AF_INET:
break; break;
case AF_INET6: case AF_INET6:
addressType = 6; addressType = 6;
break; break;
default: // we currently only push IP addresses default: // we currently only push IP addresses
++p; ++p;
continue; continue;
} }
outp->append((uint8_t)0); // no flags outp->append((uint8_t)0); // no flags
outp->append((uint16_t)0); // no extensions outp->append((uint16_t)0); // no extensions
outp->append(addressType); outp->append(addressType);
outp->append((uint8_t)((addressType == 4) ? 6 : 18)); 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()); outp->append((uint16_t)p->port());
++count; ++count;
@ -243,11 +249,11 @@ void Peer::received(
} }
if (count) { if (count) {
Metrics::pkt_push_direct_paths_out++; 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->compress();
outp->armor(_key,true,aesKeysIfSupported()); outp->armor(_key, true, aesKeysIfSupported());
Metrics::pkt_push_direct_paths_out++; 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; delete outp;
} }
@ -260,7 +266,7 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
{ {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
Mutex::Lock _lb(_bond_m); Mutex::Lock _lb(_bond_m);
if(_bond && _bond->isReady()) { if (_bond && _bond->isReady()) {
return _bond->getAppropriatePath(now, flowId); return _bond->getAppropriatePath(now, flowId);
} }
unsigned int bestPath = ZT_MAX_PEER_NETWORK_PATHS; 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. * use the old path quality metric from protocol version 9.
*/ */
long bestPathQuality = 2147483647; 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 (_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; const long q = _paths[i].p->quality(now) / _paths[i].priority;
if (q <= bestPathQuality) { if (q <= bestPathQuality) {
bestPathQuality = q; bestPathQuality = q;
bestPath = i; bestPath = i;
} }
} }
} else { }
else {
break; break;
} }
} }
@ -288,17 +295,17 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
return SharedPtr<Path>(); 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 myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
for(int i=0;i<=ZT_INETADDRESS_MAX_SCOPE;++i) { for (int i = 0; i <= ZT_INETADDRESS_MAX_SCOPE; ++i) {
myBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; myBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS;
myBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; myBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS;
myBestV4QualityByScope[i] = 2147483647; 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); 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) { if (_paths[i].p) {
const long q = _paths[i].p->quality(now) / _paths[i].priority; const long q = _paths[i].p->quality(now) / _paths[i].priority;
const unsigned int s = (unsigned int)_paths[i].p->ipScope(); 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: case AF_INET:
if (q <= myBestV4QualityByScope[s]) { if (q <= myBestV4QualityByScope[s]) {
myBestV4QualityByScope[s] = q; myBestV4QualityByScope[s] = q;
@ -329,18 +336,19 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
} }
break; break;
} }
} else { }
else {
break; break;
} }
} }
Mutex::Lock _l2(other->_paths_m); 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) { if (other->_paths[i].p) {
const long q = other->_paths[i].p->quality(now) / other->_paths[i].priority; const long q = other->_paths[i].p->quality(now) / other->_paths[i].priority;
const unsigned int s = (unsigned int)other->_paths[i].p->ipScope(); 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: case AF_INET:
if (q <= theirBestV4QualityByScope[s]) { if (q <= theirBestV4QualityByScope[s]) {
theirBestV4QualityByScope[s] = q; theirBestV4QualityByScope[s] = q;
@ -354,7 +362,8 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
} }
break; break;
} }
} else { }
else {
break; 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 mine = ZT_MAX_PEER_NETWORK_PATHS;
unsigned int theirs = ZT_MAX_PEER_NETWORK_PATHS; unsigned int theirs = ZT_MAX_PEER_NETWORK_PATHS;
for(int s=ZT_INETADDRESS_MAX_SCOPE;s>=0;--s) { 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)) { if ((myBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS) && (theirBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) {
mine = myBestV6ByScope[s]; mine = myBestV6ByScope[s];
theirs = theirBestV6ByScope[s]; theirs = theirBestV6ByScope[s];
break; 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]; mine = myBestV4ByScope[s];
theirs = theirBestV4ByScope[s]; theirs = theirBestV4ByScope[s];
break; 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) { 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; const unsigned int completed = alt + 2;
while (alt != completed) { while (alt != completed) {
if ((alt & 1) == 0) { 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); outp.append((uint8_t)0);
other->_id.address().appendTo(outp); other->_id.address().appendTo(outp);
outp.append((uint16_t)other->_paths[theirs].p->address().port()); outp.append((uint16_t)other->_paths[theirs].p->address().port());
if (other->_paths[theirs].p->address().ss_family == AF_INET6) { if (other->_paths[theirs].p->address().ss_family == AF_INET6) {
outp.append((uint8_t)16); outp.append((uint8_t)16);
outp.append(other->_paths[theirs].p->address().rawIpData(),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.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++; Metrics::pkt_rendezvous_out++;
_paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now); _paths[mine].p->send(RR, tPtr, outp.data(), outp.size(), now);
} else { }
Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); else {
Packet outp(other->_id.address(), RR->identity.address(), Packet::VERB_RENDEZVOUS);
outp.append((uint8_t)0); outp.append((uint8_t)0);
_id.address().appendTo(outp); _id.address().appendTo(outp);
outp.append((uint16_t)_paths[mine].p->address().port()); outp.append((uint16_t)_paths[mine].p->address().port());
if (_paths[mine].p->address().ss_family == AF_INET6) { if (_paths[mine].p->address().ss_family == AF_INET6) {
outp.append((uint8_t)16); outp.append((uint8_t)16);
outp.append(_paths[mine].p->address().rawIpData(),16); outp.append(_paths[mine].p->address().rawIpData(), 16);
} else {
outp.append((uint8_t)4);
outp.append(_paths[mine].p->address().rawIpData(),4);
} }
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++; 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; ++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)ZT_PROTO_VERSION);
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
outp.append(now); outp.append(now);
RR->identity.serialize(outp,false); RR->identity.serialize(outp, false);
atAddress.serialize(outp); atAddress.serialize(outp);
outp.append((uint64_t)RR->topology->planetWorldId()); 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<World> moons(RR->topology->moons());
std::vector<uint64_t> moonsWanted(RR->topology->moonsWanted()); std::vector<uint64_t> moonsWanted(RR->topology->moonsWanted());
outp.append((uint16_t)(moons.size() + moonsWanted.size())); 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((uint8_t)m->type());
outp.append((uint64_t)m->id()); outp.append((uint64_t)m->id());
outp.append((uint64_t)m->timestamp()); 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((uint8_t)World::TYPE_MOON);
outp.append(*m); outp.append(*m);
outp.append((uint64_t)0); outp.append((uint64_t)0);
} }
outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt); outp.cryptField(_key, startCryptedPortionAt, outp.size() - startCryptedPortionAt);
Metrics::pkt_hello_out++; Metrics::pkt_hello_out++;
if (atAddress) { 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->expectReplyTo(outp.packetId());
RR->node->putPacket(tPtr,RR->node->lowBandwidthModeEnabled() ? localSocket : -1,atAddress,outp.data(),outp.size()); RR->node->putPacket(tPtr, RR->node->lowBandwidthModeEnabled() ? localSocket : -1, atAddress, outp.data(), outp.size());
} else { }
else {
RR->node->expectReplyTo(outp.packetId()); 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))) ) { if ((! sendFullHello) && (_vProto >= 5) && (! ((_vMajor == 1) && (_vMinor == 1) && (_vRevision == 0)))) {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); Packet outp(_id.address(), RR->identity.address(), Packet::VERB_ECHO);
outp.armor(_key,true,aesKeysIfSupported()); outp.armor(_key, true, aesKeysIfSupported());
Metrics::pkt_echo_out++; Metrics::pkt_echo_out++;
RR->node->expectReplyTo(outp.packetId()); RR->node->expectReplyTo(outp.packetId());
RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); RR->node->putPacket(tPtr, localSocket, atAddress, outp.data(), outp.size());
} else { }
sendHELLO(tPtr,localSocket,atAddress,now); 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) { if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) {
_lastTriedMemorizedPath = now; _lastTriedMemorizedPath = now;
InetAddress mp; InetAddress mp;
if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) { if (RR->node->externalPathLookup(tPtr, _id.address(), -1, mp)) {
attemptToContactAt(tPtr,-1,mp,now,true); 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); Mutex::Lock _l(_bond_m);
/** /**
@ -493,9 +507,9 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
*/ */
int numAlivePaths = 0; int numAlivePaths = 0;
bool atLeastOneNonExpired = false; 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) {
if(_paths[i].p->alive(now)) { if (_paths[i].p->alive(now)) {
numAlivePaths++; numAlivePaths++;
} }
if ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) { if ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) {
@ -504,21 +518,21 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
} }
} }
if (_bond) { if (_bond) {
if (numAlivePaths == 0 && !atLeastOneNonExpired) { if (numAlivePaths == 0 && ! atLeastOneNonExpired) {
_bond = SharedPtr<Bond>(); _bond = SharedPtr<Bond>();
RR->bc->destroyBond(_id.address().toInt()); RR->bc->destroyBond(_id.address().toInt());
} }
return; return;
} }
_localMultipathSupported = ((numAlivePaths >= 1) && (RR->bc->inUse()) && (ZT_PROTO_VERSION > 9)); _localMultipathSupported = ((numAlivePaths >= 1) && (RR->bc->inUse()) && (ZT_PROTO_VERSION > 9));
if (_localMultipathSupported && !_bond) { if (_localMultipathSupported && ! _bond) {
if (RR->bc) { if (RR->bc) {
_bond = RR->bc->createBond(RR, this); _bond = RR->bc->createBond(RR, this);
/** /**
* Allow new bond to retroactively learn all paths known to this peer * Allow new bond to retroactively learn all paths known to this peer
*/ */
if (_bond) { 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) { if (_paths[i].p) {
_bond->nominatePathToBond(_paths[i].p, now); _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; 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 // redirects us its redirect target links override all other links and we
// let those old links expire. // let those old links expire.
long maxPriority = 0; 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) { if (_paths[i].p) {
maxPriority = std::max(_paths[i].priority,maxPriority); maxPriority = std::max(_paths[i].priority, maxPriority);
} else { }
else {
break; break;
} }
} }
bool deletionOccurred = false; 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) { if (_paths[i].p) {
// Clean expired and reduced priority paths // Clean expired and reduced priority paths
if ( ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority) ) { if (((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority)) {
if ((sendFullHello)||(_paths[i].p->needsHeartbeat(now))) { if ((sendFullHello) || (_paths[i].p->needsHeartbeat(now))) {
attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello); attemptToContactAt(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), now, sendFullHello);
_paths[i].p->sent(now); _paths[i].p->sent(now);
sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2;
} }
} else { }
else {
_paths[i] = _PeerPath(); _paths[i] = _PeerPath();
deletionOccurred = true; deletionOccurred = true;
} }
} }
if (!_paths[i].p || deletionOccurred) { if (! _paths[i].p || deletionOccurred) {
for(unsigned int j=i;j<ZT_MAX_PEER_NETWORK_PATHS;++j) { for (unsigned int j = i; j < ZT_MAX_PEER_NETWORK_PATHS; ++j) {
if (_paths[j].p && i != j) { if (_paths[j].p && i != j) {
_paths[i] = _paths[j]; _paths[i] = _paths[j];
_paths[j] = _PeerPath(); _paths[j] = _PeerPath();
@ -582,7 +598,7 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
} }
#ifndef ZT_NO_PEER_METRICS #ifndef ZT_NO_PEER_METRICS
uint16_t alive_path_count_tmp = 0, dead_path_count_tmp = 0; 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) {
if (_paths[i].p->alive(now)) { if (_paths[i].p->alive(now)) {
alive_path_count_tmp++; alive_path_count_tmp++;
@ -602,25 +618,26 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
return sent; 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)); SharedPtr<Path> np(RR->topology->getPath(originatingPath->localSocket(), remoteAddress));
RR->t->peerRedirected(tPtr,0,*this,np); 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); Mutex::Lock _l(_paths_m);
// New priority is higher than the priority of the originating path (if known) // New priority is higher than the priority of the originating path (if known)
long newPriority = 1; 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) {
if (_paths[i].p == originatingPath) { if (_paths[i].p == originatingPath) {
newPriority = _paths[i].priority; newPriority = _paths[i].priority;
break; break;
} }
} else { }
else {
break; 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 // Erase any paths with lower priority than this one or that are duplicate
// IPs and add this path. // IPs and add this path.
unsigned int j = 0; 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].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) { if (i != j) {
_paths[j] = _paths[i]; _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); 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) {
if ((_paths[i].p->address().ss_family == inetAddressFamily)&&(_paths[i].p->ipScope() == scope)) { 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); attemptToContactAt(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), now, false);
_paths[i].p->sent(now); _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; break;
} }
} }
} }
void Peer::recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId, 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)
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
{ {
#ifndef ZT_NO_PEER_METRICS #ifndef ZT_NO_PEER_METRICS
_outgoing_packet++; _outgoing_packet++;
@ -691,12 +708,11 @@ void Peer::recordIncomingInvalidPacket(const SharedPtr<Path>& path)
} }
} }
void Peer::recordIncomingPacket(const SharedPtr<Path> &path, const uint64_t packetId, 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)
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
{ {
if (_localMultipathSupported && _bond) { if (_localMultipathSupported && _bond) {
_bond->recordIncomingPacket(path, packetId, payloadLength, verb, flowId, now); _bond->recordIncomingPacket(path, packetId, payloadLength, verb, flowId, now);
} }
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

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

View file

@ -4,16 +4,17 @@ D. J. Bernstein
Public domain. Public domain.
*/ */
#include "Constants.hpp"
#include "Poly1305.hpp" #include "Poly1305.hpp"
#include <stdio.h> #include "Constants.hpp"
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#pragma warning(disable: 4146) #pragma warning(disable : 4146)
#endif #endif
namespace ZeroTier { namespace ZeroTier {
@ -21,8 +22,8 @@ namespace ZeroTier {
namespace { namespace {
typedef struct poly1305_context { typedef struct poly1305_context {
size_t aligner; size_t aligner;
unsigned char opaque[136]; unsigned char opaque[136];
} poly1305_context; } 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)) #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 // 128-bit implementation for MSC and GCC from Poly1305-donna
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <intrin.h> #include <intrin.h>
typedef struct uint128_t { typedef struct uint128_t {
unsigned long long lo; unsigned long long lo;
unsigned long long hi; unsigned long long hi;
} uint128_t; } uint128_t;
#define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi) #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 ADD(out, in) \
#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))) unsigned long long t = out.lo; \
#define LO(in) (in.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) // #define POLY1305_NOINLINE __declspec(noinline)
#elif defined(__GNUC__) #elif defined(__GNUC__)
#if defined(__SIZEOF_INT128__) #if defined(__SIZEOF_INT128__)
typedef unsigned __int128 uint128_t; typedef unsigned __int128 uint128_t;
#else #else
typedef unsigned uint128_t __attribute__((mode(TI))); typedef unsigned uint128_t __attribute__((mode(TI)));
#endif #endif
#define MUL(out, x, y) out = ((uint128_t)x * y) #define MUL(out, x, y) out = ((uint128_t)x * y)
#define ADD(out, in) out += in #define ADD(out, in) out += in
#define ADDLO(out, in) out += in #define ADDLO(out, in) out += in
#define SHR(in, shift) (unsigned long long)(in >> (shift)) #define SHR(in, shift) (unsigned long long)(in >> (shift))
#define LO(in) (unsigned long long)(in) #define LO(in) (unsigned long long)(in)
// #define POLY1305_NOINLINE __attribute__((noinline)) // #define POLY1305_NOINLINE __attribute__((noinline))
#endif #endif
@ -65,192 +76,228 @@ typedef struct poly1305_context {
/* 17 + sizeof(size_t) + 8*sizeof(unsigned long long) */ /* 17 + sizeof(size_t) + 8*sizeof(unsigned long long) */
typedef struct poly1305_state_internal_t { typedef struct poly1305_state_internal_t {
unsigned long long r[3]; unsigned long long r[3];
unsigned long long h[3]; unsigned long long h[3];
unsigned long long pad[2]; unsigned long long pad[2];
size_t leftover; size_t leftover;
unsigned char buffer[poly1305_block_size]; unsigned char buffer[poly1305_block_size];
unsigned char final; unsigned char final;
} poly1305_state_internal_t; } poly1305_state_internal_t;
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN) #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 return (
(((unsigned long long)(p[0] & 0xff) ) | ((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[1] & 0xff) << 8) | | ((unsigned long long)(p[5] & 0xff) << 40) | ((unsigned long long)(p[6] & 0xff) << 48) | ((unsigned long long)(p[7] & 0xff) << 56));
((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 #else
#define U8TO64(p) (*reinterpret_cast<const unsigned long long *>(p)) #define U8TO64(p) (*reinterpret_cast<const unsigned long long*>(p))
#endif #endif
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN) #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[0] = (v) & 0xff;
p[1] = (v >> 8) & 0xff; p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff; p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff; p[3] = (v >> 24) & 0xff;
p[4] = (v >> 32) & 0xff; p[4] = (v >> 32) & 0xff;
p[5] = (v >> 40) & 0xff; p[5] = (v >> 40) & 0xff;
p[6] = (v >> 48) & 0xff; p[6] = (v >> 48) & 0xff;
p[7] = (v >> 56) & 0xff; p[7] = (v >> 56) & 0xff;
} }
#else #else
#define U64TO8(p,v) ((*reinterpret_cast<unsigned long long *>(p)) = (v)) #define U64TO8(p, v) ((*reinterpret_cast<unsigned long long*>(p)) = (v))
#endif #endif
static inline void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { 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; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long long t0, t1;
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
t0 = U8TO64(&key[0]); t0 = U8TO64(&key[0]);
t1 = U8TO64(&key[8]); t1 = U8TO64(&key[8]);
st->r[0] = ( t0 ) & 0xffc0fffffff; st->r[0] = (t0) & 0xffc0fffffff;
st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
st->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f; st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f;
/* h = 0 */ /* h = 0 */
st->h[0] = 0; st->h[0] = 0;
st->h[1] = 0; st->h[1] = 0;
st->h[2] = 0; st->h[2] = 0;
/* save pad for later */ /* save pad for later */
st->pad[0] = U8TO64(&key[16]); st->pad[0] = U8TO64(&key[16]);
st->pad[1] = U8TO64(&key[24]); st->pad[1] = U8TO64(&key[24]);
st->leftover = 0; st->leftover = 0;
st->final = 0; st->final = 0;
} }
static inline void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { 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; const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */
unsigned long long s1,s2; unsigned long long r0, r1, r2;
unsigned long long h0,h1,h2; unsigned long long s1, s2;
unsigned long long c; unsigned long long h0, h1, h2;
uint128_t d0,d1,d2,d; unsigned long long c;
uint128_t d0, d1, d2, d;
r0 = st->r[0]; r0 = st->r[0];
r1 = st->r[1]; r1 = st->r[1];
r2 = st->r[2]; r2 = st->r[2];
h0 = st->h[0]; h0 = st->h[0];
h1 = st->h[1]; h1 = st->h[1];
h2 = st->h[2]; h2 = st->h[2];
s1 = r1 * (5 << 2); s1 = r1 * (5 << 2);
s2 = r2 * (5 << 2); s2 = r2 * (5 << 2);
while (bytes >= poly1305_block_size) { while (bytes >= poly1305_block_size) {
unsigned long long t0,t1; unsigned long long t0, t1;
/* h += m[i] */ /* h += m[i] */
t0 = U8TO64(&m[0]); t0 = U8TO64(&m[0]);
t1 = U8TO64(&m[8]); t1 = U8TO64(&m[8]);
h0 += (( t0 ) & 0xfffffffffff); h0 += ((t0) & 0xfffffffffff);
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit; h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit;
/* h *= r */ /* h *= r */
MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d); MUL(d0, h0, r0);
MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d); MUL(d, h1, s2);
MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d); 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 */ /* (partial) h %= p */
c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff; c = SHR(d0, 44);
ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff; h0 = LO(d0) & 0xfffffffffff;
ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff; ADDLO(d1, c);
h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff; c = SHR(d1, 44);
h1 += c; 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; m += poly1305_block_size;
bytes -= poly1305_block_size; bytes -= poly1305_block_size;
} }
st->h[0] = h0; st->h[0] = h0;
st->h[1] = h1; st->h[1] = h1;
st->h[2] = h2; st->h[2] = h2;
} }
static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { 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; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long long g0,g1,g2; unsigned long long h0, h1, h2, c;
unsigned long long t0,t1; unsigned long long g0, g1, g2;
unsigned long long t0, t1;
/* process the remaining block */ /* process the remaining block */
if (st->leftover) { if (st->leftover) {
size_t i = st->leftover; size_t i = st->leftover;
st->buffer[i] = 1; st->buffer[i] = 1;
for (i = i + 1; i < poly1305_block_size; i++) { for (i = i + 1; i < poly1305_block_size; i++) {
st->buffer[i] = 0; st->buffer[i] = 0;
} }
st->final = 1; st->final = 1;
poly1305_blocks(st, st->buffer, poly1305_block_size); poly1305_blocks(st, st->buffer, poly1305_block_size);
} }
/* fully carry h */ /* fully carry h */
h0 = st->h[0]; h0 = st->h[0];
h1 = st->h[1]; h1 = st->h[1];
h2 = st->h[2]; h2 = st->h[2];
c = (h1 >> 44); h1 &= 0xfffffffffff; c = (h1 >> 44);
h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; h1 &= 0xfffffffffff;
h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; h2 += c;
h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff; c = (h2 >> 42);
h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; h2 &= 0x3ffffffffff;
h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; h0 += c * 5;
h1 += c; 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 */ /* compute h + -p */
g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff; g0 = h0 + 5;
g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff; c = (g0 >> 44);
g2 = h2 + c - ((unsigned long long)1 << 42); 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 */ /* select h if h < p, or h + -p if h >= p */
c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1; c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1;
g0 &= c; g0 &= c;
g1 &= c; g1 &= c;
g2 &= c; g2 &= c;
c = ~c; c = ~c;
h0 = (h0 & c) | g0; h0 = (h0 & c) | g0;
h1 = (h1 & c) | g1; h1 = (h1 & c) | g1;
h2 = (h2 & c) | g2; h2 = (h2 & c) | g2;
/* h = (h + pad) */ /* h = (h + pad) */
t0 = st->pad[0]; t0 = st->pad[0];
t1 = st->pad[1]; t1 = st->pad[1];
h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff; h0 += ((t0) & 0xfffffffffff);
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff; c = (h0 >> 44);
h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff; 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) */ /* mac = h % (2^128) */
h0 = ((h0 ) | (h1 << 44)); h0 = ((h0) | (h1 << 44));
h1 = ((h1 >> 20) | (h2 << 24)); h1 = ((h1 >> 20) | (h2 << 24));
U64TO8(&mac[0], h0); U64TO8(&mac[0], h0);
U64TO8(&mac[8], h1); U64TO8(&mac[8], h1);
/* zero out the state */ /* zero out the state */
st->h[0] = 0; st->h[0] = 0;
st->h[1] = 0; st->h[1] = 0;
st->h[2] = 0; st->h[2] = 0;
st->r[0] = 0; st->r[0] = 0;
st->r[1] = 0; st->r[1] = 0;
st->r[2] = 0; st->r[2] = 0;
st->pad[0] = 0; st->pad[0] = 0;
st->pad[1] = 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) */ /* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */
typedef struct poly1305_state_internal_t { typedef struct poly1305_state_internal_t {
unsigned long r[5]; unsigned long r[5];
unsigned long h[5]; unsigned long h[5];
unsigned long pad[4]; unsigned long pad[4];
size_t leftover; size_t leftover;
unsigned char buffer[poly1305_block_size]; unsigned char buffer[poly1305_block_size];
unsigned char final; unsigned char final;
} poly1305_state_internal_t; } poly1305_state_internal_t;
/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */ /* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */
static unsigned long static unsigned long U8TO32(const unsigned char* p)
U8TO32(const unsigned char *p) { {
return return (((unsigned long)(p[0] & 0xff)) | ((unsigned long)(p[1] & 0xff) << 8) | ((unsigned long)(p[2] & 0xff) << 16) | ((unsigned long)(p[3] & 0xff) << 24));
(((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 */ /* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */
static void static void U32TO8(unsigned char* p, unsigned long v)
U32TO8(unsigned char *p, unsigned long v) { {
p[0] = (v ) & 0xff; p[0] = (v) & 0xff;
p[1] = (v >> 8) & 0xff; p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff; p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff; p[3] = (v >> 24) & 0xff;
} }
static inline void static inline void poly1305_init(poly1305_context* ctx, const unsigned char key[32])
poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff; st->r[0] = (U8TO32(&key[0])) & 0x3ffffff;
st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03; st->r[1] = (U8TO32(&key[3]) >> 2) & 0x3ffff03;
st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff; st->r[2] = (U8TO32(&key[6]) >> 4) & 0x3ffc0ff;
st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff; st->r[3] = (U8TO32(&key[9]) >> 6) & 0x3f03fff;
st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff;
/* h = 0 */ /* h = 0 */
st->h[0] = 0; st->h[0] = 0;
st->h[1] = 0; st->h[1] = 0;
st->h[2] = 0; st->h[2] = 0;
st->h[3] = 0; st->h[3] = 0;
st->h[4] = 0; st->h[4] = 0;
/* save pad for later */ /* save pad for later */
st->pad[0] = U8TO32(&key[16]); st->pad[0] = U8TO32(&key[16]);
st->pad[1] = U8TO32(&key[20]); st->pad[1] = U8TO32(&key[20]);
st->pad[2] = U8TO32(&key[24]); st->pad[2] = U8TO32(&key[24]);
st->pad[3] = U8TO32(&key[28]); st->pad[3] = U8TO32(&key[28]);
st->leftover = 0; st->leftover = 0;
st->final = 0; st->final = 0;
} }
static inline void static inline void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes)
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 */ const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */
unsigned long r0,r1,r2,r3,r4; unsigned long r0, r1, r2, r3, r4;
unsigned long s1,s2,s3,s4; unsigned long s1, s2, s3, s4;
unsigned long h0,h1,h2,h3,h4; unsigned long h0, h1, h2, h3, h4;
unsigned long long d0,d1,d2,d3,d4; unsigned long long d0, d1, d2, d3, d4;
unsigned long c; unsigned long c;
r0 = st->r[0]; r0 = st->r[0];
r1 = st->r[1]; r1 = st->r[1];
r2 = st->r[2]; r2 = st->r[2];
r3 = st->r[3]; r3 = st->r[3];
r4 = st->r[4]; r4 = st->r[4];
s1 = r1 * 5; s1 = r1 * 5;
s2 = r2 * 5; s2 = r2 * 5;
s3 = r3 * 5; s3 = r3 * 5;
s4 = r4 * 5; s4 = r4 * 5;
h0 = st->h[0]; h0 = st->h[0];
h1 = st->h[1]; h1 = st->h[1];
h2 = st->h[2]; h2 = st->h[2];
h3 = st->h[3]; h3 = st->h[3];
h4 = st->h[4]; h4 = st->h[4];
while (bytes >= poly1305_block_size) { while (bytes >= poly1305_block_size) {
/* h += m[i] */ /* h += m[i] */
h0 += (U8TO32(m+ 0) ) & 0x3ffffff; h0 += (U8TO32(m + 0)) & 0x3ffffff;
h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; h1 += (U8TO32(m + 3) >> 2) & 0x3ffffff;
h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; h2 += (U8TO32(m + 6) >> 4) & 0x3ffffff;
h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; h3 += (U8TO32(m + 9) >> 6) & 0x3ffffff;
h4 += (U8TO32(m+12) >> 8) | hibit; h4 += (U8TO32(m + 12) >> 8) | hibit;
/* h *= r */ /* 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); 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); 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); 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); 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); 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 */ /* (partial) h %= p */
c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; c = (unsigned long)(d0 >> 26);
d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; h0 = (unsigned long)d0 & 0x3ffffff;
d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; d1 += c;
d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; c = (unsigned long)(d1 >> 26);
d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; h1 = (unsigned long)d1 & 0x3ffffff;
h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; d2 += c;
h1 += 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; m += poly1305_block_size;
bytes -= poly1305_block_size; bytes -= poly1305_block_size;
} }
st->h[0] = h0; st->h[0] = h0;
st->h[1] = h1; st->h[1] = h1;
st->h[2] = h2; st->h[2] = h2;
st->h[3] = h3; st->h[3] = h3;
st->h[4] = h4; st->h[4] = h4;
} }
static inline void static inline void poly1305_finish(poly1305_context* ctx, unsigned char mac[16])
poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long h0,h1,h2,h3,h4,c; unsigned long h0, h1, h2, h3, h4, c;
unsigned long g0,g1,g2,g3,g4; unsigned long g0, g1, g2, g3, g4;
unsigned long long f; unsigned long long f;
unsigned long mask; unsigned long mask;
/* process the remaining block */ /* process the remaining block */
if (st->leftover) { if (st->leftover) {
size_t i = st->leftover; size_t i = st->leftover;
st->buffer[i++] = 1; st->buffer[i++] = 1;
for (; i < poly1305_block_size; i++) { for (; i < poly1305_block_size; i++) {
st->buffer[i] = 0; st->buffer[i] = 0;
} }
st->final = 1; st->final = 1;
poly1305_blocks(st, st->buffer, poly1305_block_size); poly1305_blocks(st, st->buffer, poly1305_block_size);
} }
/* fully carry h */ /* fully carry h */
h0 = st->h[0]; h0 = st->h[0];
h1 = st->h[1]; h1 = st->h[1];
h2 = st->h[2]; h2 = st->h[2];
h3 = st->h[3]; h3 = st->h[3];
h4 = st->h[4]; h4 = st->h[4];
c = h1 >> 26; h1 = h1 & 0x3ffffff; c = h1 >> 26;
h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; h1 = h1 & 0x3ffffff;
h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; h2 += c;
h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; c = h2 >> 26;
h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; h2 = h2 & 0x3ffffff;
h1 += c; 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 */ /* compute h + -p */
g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; g0 = h0 + 5;
g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; c = g0 >> 26;
g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; g0 &= 0x3ffffff;
g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; g1 = h1 + c;
g4 = h4 + c - (1 << 26); 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 */ /* select h if h < p, or h + -p if h >= p */
mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1;
g0 &= mask; g0 &= mask;
g1 &= mask; g1 &= mask;
g2 &= mask; g2 &= mask;
g3 &= mask; g3 &= mask;
g4 &= mask; g4 &= mask;
mask = ~mask; mask = ~mask;
h0 = (h0 & mask) | g0; h0 = (h0 & mask) | g0;
h1 = (h1 & mask) | g1; h1 = (h1 & mask) | g1;
h2 = (h2 & mask) | g2; h2 = (h2 & mask) | g2;
h3 = (h3 & mask) | g3; h3 = (h3 & mask) | g3;
h4 = (h4 & mask) | g4; h4 = (h4 & mask) | g4;
/* h = h % (2^128) */ /* h = h % (2^128) */
h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; h0 = ((h0) | (h1 << 26)) & 0xffffffff;
h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
/* mac = (h + pad) % (2^128) */ /* mac = (h + pad) % (2^128) */
f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f; f = (unsigned long long)h0 + st->pad[0];
f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; h0 = (unsigned long)f;
f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; f = (unsigned long long)h1 + st->pad[1] + (f >> 32);
f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; 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 + 0, h0);
U32TO8(mac + 4, h1); U32TO8(mac + 4, h1);
U32TO8(mac + 8, h2); U32TO8(mac + 8, h2);
U32TO8(mac + 12, h3); U32TO8(mac + 12, h3);
/* zero out the state */ /* zero out the state */
st->h[0] = 0; st->h[0] = 0;
st->h[1] = 0; st->h[1] = 0;
st->h[2] = 0; st->h[2] = 0;
st->h[3] = 0; st->h[3] = 0;
st->h[4] = 0; st->h[4] = 0;
st->r[0] = 0; st->r[0] = 0;
st->r[1] = 0; st->r[1] = 0;
st->r[2] = 0; st->r[2] = 0;
st->r[3] = 0; st->r[3] = 0;
st->r[4] = 0; st->r[4] = 0;
st->pad[0] = 0; st->pad[0] = 0;
st->pad[1] = 0; st->pad[1] = 0;
st->pad[2] = 0; st->pad[2] = 0;
st->pad[3] = 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) { 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)
{ {
poly1305_context ctx; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
poly1305_init(&ctx,reinterpret_cast<const unsigned char *>(key)); size_t i;
poly1305_update(&ctx,reinterpret_cast<const unsigned char *>(data),(size_t)len);
poly1305_finish(&ctx,reinterpret_cast<unsigned char *>(auth)); /* 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 * keystream as a one-time-use key. These 32 bytes are then discarded and
* the packet is encrypted with the next N bytes. * the packet is encrypted with the next N bytes.
*/ */
class Poly1305 class Poly1305 {
{ public:
public:
/** /**
* Compute a one-time authentication code * Compute a one-time authentication code
* *
@ -41,9 +40,9 @@ public:
* @param len Length of data to authenticate in bytes * @param len Length of data to authenticate in bytes
* @param key 32-byte one-time use key to authenticate data (must not be reused) * @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 #endif

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -22,8 +22,8 @@
#define ZT_SHA512_DIGEST_SIZE 64 #define ZT_SHA512_DIGEST_SIZE 64
#define ZT_SHA384_DIGEST_SIZE 48 #define ZT_SHA384_DIGEST_SIZE 48
#define ZT_SHA512_BLOCK_SIZE 128 #define ZT_SHA512_BLOCK_SIZE 128
#define ZT_SHA384_BLOCK_SIZE 128 #define ZT_SHA384_BLOCK_SIZE 128
#define ZT_HMACSHA384_LEN 48 #define ZT_HMACSHA384_LEN 48
@ -32,34 +32,34 @@ namespace ZeroTier {
// SHA384 and SHA512 are actually in the standard libraries on MacOS and iOS // SHA384 and SHA512 are actually in the standard libraries on MacOS and iOS
#ifdef __APPLE__ #ifdef __APPLE__
#define ZT_HAVE_NATIVE_SHA512 1 #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_CTX ctx;
CC_SHA512_Init(&ctx); CC_SHA512_Init(&ctx);
CC_SHA512_Update(&ctx,data,len); CC_SHA512_Update(&ctx, data, len);
CC_SHA512_Final(reinterpret_cast<unsigned char *>(digest),&ctx); 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_SHA512_CTX ctx;
CC_SHA384_Init(&ctx); CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx,data,len); CC_SHA384_Update(&ctx, data, len);
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx); 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_SHA512_CTX ctx;
CC_SHA384_Init(&ctx); CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx,data0,len0); CC_SHA384_Update(&ctx, data0, len0);
CC_SHA384_Update(&ctx,data1,len1); CC_SHA384_Update(&ctx, data1, len1);
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx); CC_SHA384_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
} }
#endif #endif
#ifndef ZT_HAVE_NATIVE_SHA512 #ifndef ZT_HAVE_NATIVE_SHA512
void SHA512(void *digest,const void *data,unsigned int len); 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* data, unsigned int len);
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);
#endif #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 msglen Length of message
* @param mac Buffer to fill with result * @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 * 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 iter Key iteration for generation of multiple keys for the same label/context
* @param out Output to receive derived key * @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 #endif

File diff suppressed because it is too large Load diff

View file

@ -7,32 +7,36 @@
#ifndef ZT_SALSA20_HPP #ifndef ZT_SALSA20_HPP
#define ZT_SALSA20_HPP #define ZT_SALSA20_HPP
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.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 #define ZT_SALSA20_SSE 1
#endif #endif
#ifdef ZT_SALSA20_SSE #ifdef ZT_SALSA20_SSE
#include <emmintrin.h> #include <emmintrin.h>
#endif // ZT_SALSA20_SSE #endif // ZT_SALSA20_SSE
namespace ZeroTier { namespace ZeroTier {
/** /**
* Salsa20 stream cipher * Salsa20 stream cipher
*/ */
class Salsa20 class Salsa20 {
{ public:
public: Salsa20()
Salsa20() {} {
~Salsa20() { Utils::burn(&_state,sizeof(_state)); } }
~Salsa20()
{
Utils::burn(&_state, sizeof(_state));
}
/** /**
* XOR d with s * XOR d with s
@ -45,48 +49,48 @@ public:
* @param s Source bytes to XOR with destination * @param s Source bytes to XOR with destination
* @param len Length of s and d * @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 #ifdef ZT_SALSA20_SSE
while (len >= 128) { while (len >= 128) {
__m128i s0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s)); __m128i s0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s));
__m128i s1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 16)); __m128i s1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 16));
__m128i s2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 32)); __m128i s2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 32));
__m128i s3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 48)); __m128i s3 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 48));
__m128i s4 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 64)); __m128i s4 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 64));
__m128i s5 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 80)); __m128i s5 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 80));
__m128i s6 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 96)); __m128i s6 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 96));
__m128i s7 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 112)); __m128i s7 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 112));
__m128i d0 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d)); __m128i d0 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d));
__m128i d1 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 16)); __m128i d1 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 16));
__m128i d2 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 32)); __m128i d2 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 32));
__m128i d3 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 48)); __m128i d3 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 48));
__m128i d4 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 64)); __m128i d4 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 64));
__m128i d5 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 80)); __m128i d5 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 80));
__m128i d6 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 96)); __m128i d6 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 96));
__m128i d7 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 112)); __m128i d7 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 112));
d0 = _mm_xor_si128(d0,s0); d0 = _mm_xor_si128(d0, s0);
d1 = _mm_xor_si128(d1,s1); d1 = _mm_xor_si128(d1, s1);
d2 = _mm_xor_si128(d2,s2); d2 = _mm_xor_si128(d2, s2);
d3 = _mm_xor_si128(d3,s3); d3 = _mm_xor_si128(d3, s3);
d4 = _mm_xor_si128(d4,s4); d4 = _mm_xor_si128(d4, s4);
d5 = _mm_xor_si128(d5,s5); d5 = _mm_xor_si128(d5, s5);
d6 = _mm_xor_si128(d6,s6); d6 = _mm_xor_si128(d6, s6);
d7 = _mm_xor_si128(d7,s7); d7 = _mm_xor_si128(d7, s7);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d),d0); _mm_storeu_si128(reinterpret_cast<__m128i*>(d), d0);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 16),d1); _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 + 32), d2);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 48),d3); _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 + 64), d4);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 80),d5); _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 + 96), d6);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 112),d7); _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 112), d7);
s += 128; s += 128;
d += 128; d += 128;
len -= 128; len -= 128;
} }
while (len >= 16) { 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; s += 16;
d += 16; d += 16;
len -= 16; len -= 16;
@ -94,10 +98,10 @@ public:
#else #else
#ifndef ZT_NO_TYPE_PUNNING #ifndef ZT_NO_TYPE_PUNNING
while (len >= 16) { 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; s += 8;
d += 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; s += 8;
d += 8; d += 8;
len -= 16; len -= 16;
@ -114,9 +118,9 @@ public:
* @param key 256-bit (32 byte) key * @param key 256-bit (32 byte) key
* @param iv 64-bit initialization vector * @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 key Key bits
* @param iv 64-bit initialization vector * @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 * Encrypt/decrypt data using Salsa20/12
@ -134,7 +138,7 @@ public:
* @param out Output buffer * @param out Output buffer
* @param bytes Length of data * @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 * Encrypt/decrypt data using Salsa20/20
@ -143,17 +147,17 @@ public:
* @param out Output buffer * @param out Output buffer
* @param bytes Length of data * @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 { union {
#ifdef ZT_SALSA20_SSE #ifdef ZT_SALSA20_SSE
__m128i v[4]; __m128i v[4];
#endif // ZT_SALSA20_SSE #endif // ZT_SALSA20_SSE
uint32_t i[16]; uint32_t i[16];
} _state; } _state;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #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 <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <set>
#include <vector> #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 // Entry timeout -- make it fairly long since this is just to prevent stale buildup
#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000 #define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000
namespace ZeroTier { namespace ZeroTier {
class _ResetWithinScope class _ResetWithinScope {
{ public:
public: _ResetWithinScope(void* tPtr, int64_t now, int inetAddressFamily, InetAddress::IpScope scope) : _now(now), _tPtr(tPtr), _family(inetAddressFamily), _scope(scope)
_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; uint64_t _now;
void *_tPtr; void* _tPtr;
int _family; int _family;
InetAddress::IpScope _scope; InetAddress::IpScope _scope;
}; };
SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : SelfAwareness::SelfAwareness(const RuntimeEnvironment* renv) : RR(renv), _phy(128)
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(); 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; return;
} }
Mutex::Lock _l(_phy_m); 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 // 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.mySurface = myPhysicalAddress;
entry.ts = now; 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. // due to multiple reports of endpoint change.
// Don't use 'entry' after this since hash table gets modified. // Don't use 'entry' after this since hash table gets modified.
{ {
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); Hashtable<PhySurfaceKey, PhySurfaceEntry>::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceKey* k = (PhySurfaceKey*)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0; PhySurfaceEntry* e = (PhySurfaceEntry*)0;
while (i.next(k,e)) { while (i.next(k, e)) {
if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope)) { if ((k->reporterPhysicalAddress != reporterPhysicalAddress) && (k->scope == scope)) {
_phy.erase(*k); _phy.erase(*k);
} }
} }
} }
// Reset all paths within this scope and address family // Reset all paths within this scope and address family
_ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); _ResetWithinScope rset(tPtr, now, myPhysicalAddress.ss_family, (InetAddress::IpScope)scope);
RR->topology->eachPeer<_ResetWithinScope &>(rset); RR->topology->eachPeer<_ResetWithinScope&>(rset);
} else { }
else {
// Otherwise just update DB to use to determine external surface info // Otherwise just update DB to use to determine external surface info
entry.mySurface = myPhysicalAddress; entry.mySurface = myPhysicalAddress;
entry.ts = now; entry.ts = now;
@ -105,10 +104,10 @@ std::vector<InetAddress> SelfAwareness::whoami()
{ {
std::vector<InetAddress> surfaceAddresses; std::vector<InetAddress> surfaceAddresses;
Mutex::Lock _l(_phy_m); Mutex::Lock _l(_phy_m);
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); Hashtable<PhySurfaceKey, PhySurfaceEntry>::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceKey* k = (PhySurfaceKey*)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0; PhySurfaceEntry* e = (PhySurfaceEntry*)0;
while (i.next(k,e)) { while (i.next(k, e)) {
if (std::find(surfaceAddresses.begin(), surfaceAddresses.end(), e->mySurface) == surfaceAddresses.end()) { if (std::find(surfaceAddresses.begin(), surfaceAddresses.end(), e->mySurface) == surfaceAddresses.end()) {
surfaceAddresses.push_back(e->mySurface); surfaceAddresses.push_back(e->mySurface);
} }
@ -119,14 +118,14 @@ std::vector<InetAddress> SelfAwareness::whoami()
void SelfAwareness::clean(int64_t now) void SelfAwareness::clean(int64_t now)
{ {
Mutex::Lock _l(_phy_m); Mutex::Lock _l(_phy_m);
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); Hashtable<PhySurfaceKey, PhySurfaceEntry>::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceKey* k = (PhySurfaceKey*)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0; PhySurfaceEntry* e = (PhySurfaceEntry*)0;
while (i.next(k,e)) { while (i.next(k, e)) {
if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) { if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) {
_phy.erase(*k); _phy.erase(*k);
} }
} }
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -14,32 +14,32 @@
#ifndef ZT_N_SWITCH_HPP #ifndef ZT_N_SWITCH_HPP
#define 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 <map>
#include <set> #include <set>
#include <vector> #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 */ /* Ethernet frame types that might be relevant to us */
#define ZT_ETHERTYPE_IPV4 0x0800 #define ZT_ETHERTYPE_IPV4 0x0800
#define ZT_ETHERTYPE_ARP 0x0806 #define ZT_ETHERTYPE_ARP 0x0806
#define ZT_ETHERTYPE_RARP 0x8035 #define ZT_ETHERTYPE_RARP 0x8035
#define ZT_ETHERTYPE_ATALK 0x809b #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_A 0x8137
#define ZT_ETHERTYPE_IPX_B 0x8138 #define ZT_ETHERTYPE_IPX_B 0x8138
#define ZT_ETHERTYPE_IPV6 0x86dd #define ZT_ETHERTYPE_IPV6 0x86dd
namespace ZeroTier { namespace ZeroTier {
@ -54,20 +54,19 @@ class Peer;
* packets from tap devices, and this sends them where they need to go and * 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. * wraps/unwraps accordingly. It also handles queues and timeouts and such.
*/ */
class Switch class Switch {
{
struct ManagedQueue; struct ManagedQueue;
struct TXQueueEntry; struct TXQueueEntry;
friend class SharedPtr<Peer>; friend class SharedPtr<Peer>;
typedef struct { typedef struct {
TXQueueEntry *p; TXQueueEntry* p;
bool ok_to_drop; bool ok_to_drop;
} dqr; } dqr;
public: public:
Switch(const RuntimeEnvironment *renv); Switch(const RuntimeEnvironment* renv);
/** /**
* Called when a packet is received from the real network * Called when a packet is received from the real network
@ -78,7 +77,7 @@ public:
* @param data Packet data * @param data Packet data
* @param len Packet length * @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. * Returns whether our bonding or balancing policy is aware of flows.
@ -97,7 +96,7 @@ public:
* @param data Ethernet payload * @param data Ethernet payload
* @param len Frame length * @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 * 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 q The TX queue that is being dequeued from
* @param now Current time * @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. * Presents a packet to the AQM scheduler.
@ -125,14 +124,14 @@ public:
* @param encrypt Encrypt packet payload? (always true except for HELLO) * @param encrypt Encrypt packet payload? (always true except for HELLO)
* @param qosBucket Which bucket the rule-system determined this packet should fall into * @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 * 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 * @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 * 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 isNew Whether or not this queue is in the NEW list
* @param now Current time * @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 * 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 packet Packet to send (buffer may be modified)
* @param encrypt Encrypt packet payload? (always true except for HELLO) * @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 * Request WHOIS on a given address
@ -180,7 +179,7 @@ public:
* @param now Current time * @param now Current time
* @param addr Address to look up * @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 * 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 tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param peer New peer * @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 * Perform retries and other periodic timer tasks
@ -202,33 +201,34 @@ public:
* @param now Current time * @param now Current time
* @return Number of milliseconds until doTimerTasks() should be run again * @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: private:
bool _shouldUnite(const int64_t now,const Address &source,const Address &destination); 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 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 _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); void _recordOutgoingPacketMetrics(const Packet& p);
const RuntimeEnvironment *const RR; const RuntimeEnvironment* const RR;
int64_t _lastBeaconResponse; int64_t _lastBeaconResponse;
volatile int64_t _lastCheckedQueues; volatile int64_t _lastCheckedQueues;
// Time we last sent a WHOIS request for each address // Time we last sent a WHOIS request for each address
Hashtable< Address,int64_t > _lastSentWhoisRequest; Hashtable<Address, int64_t> _lastSentWhoisRequest;
Mutex _lastSentWhoisRequest_m; Mutex _lastSentWhoisRequest_m;
// Packets waiting for WHOIS replies or other decode info or missing fragments // Packets waiting for WHOIS replies or other decode info or missing fragments
struct RXQueueEntry struct RXQueueEntry {
{ RXQueueEntry() : timestamp(0)
RXQueueEntry() : timestamp(0) {} {
volatile int64_t timestamp; // 0 if entry is not in use }
volatile int64_t timestamp; // 0 if entry is not in use
volatile uint64_t packetId; volatile uint64_t packetId;
IncomingPacket frag0; // head of packet IncomingPacket frag0; // head of packet
Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any) Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any)
unsigned int totalFragments; // 0 if only frag0 received, waiting for frags unsigned int totalFragments; // 0 if only frag0 received, waiting for frags
uint32_t haveFragments; // bit mask, LSB to MSB uint32_t haveFragments; // bit mask, LSB to MSB
volatile bool complete; // if true, packet is complete volatile bool complete; // if true, packet is complete
volatile int32_t flowId; volatile int32_t flowId;
Mutex lock; Mutex lock;
}; };
@ -236,12 +236,12 @@ private:
AtomicCounter _rxQueuePtr; AtomicCounter _rxQueuePtr;
// Returns matching or next available RX queue entry // 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()); const unsigned int current = static_cast<unsigned int>(_rxQueuePtr.load());
for(unsigned int k=1;k<=ZT_RX_QUEUE_SIZE;++k) { for (unsigned int k = 1; k <= ZT_RX_QUEUE_SIZE; ++k) {
RXQueueEntry *rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]); RXQueueEntry* rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]);
if ((rq->packetId == packetId)&&(rq->timestamp)) { if ((rq->packetId == packetId) && (rq->timestamp)) {
return rq; return rq;
} }
} }
@ -250,62 +250,64 @@ private:
} }
// Returns current entry in rx queue ring buffer and increments ring pointer // 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]); return &(_rxQueue[static_cast<unsigned int>((++_rxQueuePtr) - 1) % ZT_RX_QUEUE_SIZE]);
} }
// ZeroTier-layer TX queue entry // ZeroTier-layer TX queue entry
struct TXQueueEntry struct TXQueueEntry {
{ TXQueueEntry()
TXQueueEntry() {} {
TXQueueEntry(Address d,uint64_t ct,const Packet &p,bool enc,int32_t fid) : }
dest(d), TXQueueEntry(Address d, uint64_t ct, const Packet& p, bool enc, int32_t fid) : dest(d), creationTime(ct), packet(p), encrypt(enc), flowId(fid)
creationTime(ct), {
packet(p), }
encrypt(enc),
flowId(fid) {}
Address dest; Address dest;
uint64_t creationTime; 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; bool encrypt;
int32_t flowId; int32_t flowId;
}; };
std::list< TXQueueEntry > _txQueue; std::list<TXQueueEntry> _txQueue;
Mutex _txQueue_m; Mutex _txQueue_m;
Mutex _aqm_m; Mutex _aqm_m;
// Tracks sending of VERB_RENDEZVOUS to relaying peers // Tracks sending of VERB_RENDEZVOUS to relaying peers
struct _LastUniteKey struct _LastUniteKey {
{ _LastUniteKey() : x(0), y(0)
_LastUniteKey() : x(0),y(0) {} {
_LastUniteKey(const Address &a1,const Address &a2) }
_LastUniteKey(const Address& a1, const Address& a2)
{ {
if (a1 > a2) { if (a1 > a2) {
x = a2.toInt(); x = a2.toInt();
y = a1.toInt(); y = a1.toInt();
} else { }
else {
x = a1.toInt(); x = a1.toInt();
y = a2.toInt(); y = a2.toInt();
} }
} }
inline unsigned long hashCode() const { return ((unsigned long)x ^ (unsigned long)y); } inline unsigned long hashCode() const
inline bool operator==(const _LastUniteKey &k) const { return ((x == k.x)&&(y == k.y)); } {
uint64_t x,y; 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; Mutex _lastUniteAttempt_m;
// Queue with additional flow state variables // Queue with additional flow state variables
struct ManagedQueue struct ManagedQueue {
{ ManagedQueue(int id) : id(id), byteCredit(ZT_AQM_QUANTUM), byteLength(0), dropping(false)
ManagedQueue(int id) : {
id(id), }
byteCredit(ZT_AQM_QUANTUM),
byteLength(0),
dropping(false)
{}
int id; int id;
int byteCredit; int byteCredit;
int byteLength; int byteLength;
@ -314,19 +316,18 @@ private:
uint64_t drop_next; uint64_t drop_next;
bool dropping; bool dropping;
uint64_t drop_next_time; 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 // To implement fq_codel we need to maintain a queue of queues
struct NetworkQoSControlBlock struct NetworkQoSControlBlock {
{
int _currEnqueuedPackets; int _currEnqueuedPackets;
std::vector<ManagedQueue *> newQueues; std::vector<ManagedQueue*> newQueues;
std::vector<ManagedQueue *> oldQueues; std::vector<ManagedQueue*> oldQueues;
std::vector<ManagedQueue *> inactiveQueues; std::vector<ManagedQueue*> inactiveQueues;
}; };
std::map<uint64_t,NetworkQoSControlBlock*> _netQueueControlBlock; std::map<uint64_t, NetworkQoSControlBlock*> _netQueueControlBlock;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

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

View file

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

View file

@ -11,63 +11,79 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "Topology.hpp" #include "Topology.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp" #include "Buffer.hpp"
#include "Constants.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "NetworkConfig.hpp" #include "NetworkConfig.hpp"
#include "Buffer.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp" #include "Switch.hpp"
namespace ZeroTier { namespace ZeroTier {
#define ZT_DEFAULT_WORLD_LENGTH 570 #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) : Topology::Topology(const RuntimeEnvironment* renv, void* tPtr) : RR(renv), _numConfiguredPhysicalPaths(0), _amUpstream(false)
RR(renv),
_numConfiguredPhysicalPaths(0),
_amUpstream(false)
{ {
uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
uint64_t idtmp[2]; uint64_t idtmp[2];
idtmp[0] = 0; idtmp[0] = 0;
idtmp[1] = 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) { if (n > 0) {
try { try {
World cachedPlanet; World cachedPlanet;
cachedPlanet.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp,(unsigned int)n),0); cachedPlanet.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp, (unsigned int)n), 0);
addWorld(tPtr,cachedPlanet,false); addWorld(tPtr, cachedPlanet, false);
} catch ( ... ) {} // ignore invalid cached planets }
catch (...) {
} // ignore invalid cached planets
} }
World defaultPlanet; World defaultPlanet;
{ {
Buffer<ZT_DEFAULT_WORLD_LENGTH> wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); 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 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() Topology::~Topology()
{ {
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers); Hashtable<Address, SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0; Address* a = (Address*)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0; SharedPtr<Peer>* p = (SharedPtr<Peer>*)0;
while (i.next(a,p)) { while (i.next(a, p)) {
_savePeer((void *)0,*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; SharedPtr<Peer> np;
{ {
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
SharedPtr<Peer> &hp = _peers[peer->address()]; SharedPtr<Peer>& hp = _peers[peer->address()];
if (!hp) { if (! hp) {
hp = peer; hp = peer;
} }
np = hp; np = hp;
@ -75,7 +91,7 @@ SharedPtr<Peer> Topology::addPeer(void *tPtr,const SharedPtr<Peer> &peer)
return np; 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()) { if (zta == RR->identity.address()) {
return SharedPtr<Peer>(); return SharedPtr<Peer>();
@ -83,7 +99,7 @@ SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
{ {
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta); const SharedPtr<Peer>* const ap = _peers.get(zta);
if (ap) { if (ap) {
return *ap; return *ap;
} }
@ -94,32 +110,35 @@ SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
uint64_t idbuf[2]; uint64_t idbuf[2];
idbuf[0] = zta.toInt(); idbuf[0] = zta.toInt();
idbuf[1] = 0; 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) { if (len > 0) {
buf.setSize(len); buf.setSize(len);
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
SharedPtr<Peer> &ap = _peers[zta]; SharedPtr<Peer>& ap = _peers[zta];
if (ap) { if (ap) {
return ap; return ap;
} }
ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR); ap = Peer::deserializeFromCache(RR->node->now(), tPtr, buf, RR);
if (!ap) { if (! ap) {
_peers.erase(zta); _peers.erase(zta);
} }
return SharedPtr<Peer>(); return SharedPtr<Peer>();
} }
} catch ( ... ) {} // ignore invalid identities or other strange failures }
catch (...) {
} // ignore invalid identities or other strange failures
return SharedPtr<Peer>(); return SharedPtr<Peer>();
} }
Identity Topology::getIdentity(void *tPtr,const Address &zta) Identity Topology::getIdentity(void* tPtr, const Address& zta)
{ {
if (zta == RR->identity.address()) { if (zta == RR->identity.address()) {
return RR->identity; return RR->identity;
} else { }
else {
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta); const SharedPtr<Peer>* const ap = _peers.get(zta);
if (ap) { if (ap) {
return (*ap)->identity(); return (*ap)->identity();
} }
@ -131,13 +150,13 @@ SharedPtr<Peer> Topology::getUpstreamPeer()
{ {
const int64_t now = RR->node->now(); const int64_t now = RR->node->now();
unsigned int bestq = ~((unsigned int)0); 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 _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m); Mutex::Lock _l1(_upstreams_m);
for(std::vector<Address>::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { for (std::vector<Address>::const_iterator a(_upstreamAddresses.begin()); a != _upstreamAddresses.end(); ++a) {
const SharedPtr<Peer> *p = _peers.get(*a); const SharedPtr<Peer>* p = _peers.get(*a);
if (p) { if (p) {
const unsigned int q = (*p)->relayQuality(now); const unsigned int q = (*p)->relayQuality(now);
if (q <= bestq) { if (q <= bestq) {
@ -147,25 +166,25 @@ SharedPtr<Peer> Topology::getUpstreamPeer()
} }
} }
if (!best) { if (! best) {
return SharedPtr<Peer>(); return SharedPtr<Peer>();
} }
return *best; return *best;
} }
bool Topology::isUpstream(const Identity &id) const bool Topology::isUpstream(const Identity& id) const
{ {
Mutex::Lock _l(_upstreams_m); 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); 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; 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) { if (s->second == addr) {
return true; return true;
} }
@ -173,11 +192,11 @@ bool Topology::shouldAcceptWorldUpdateFrom(const Address &addr) const
return false; return false;
} }
ZT_PeerRole Topology::role(const Address &ztaddr) const ZT_PeerRole Topology::role(const Address& ztaddr) const
{ {
Mutex::Lock _l(_upstreams_m); Mutex::Lock _l(_upstreams_m);
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { 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) { for (std::vector<World::Root>::const_iterator i(_planet.roots().begin()); i != _planet.roots().end(); ++i) {
if (i->identity.address() == ztaddr) { if (i->identity.address() == ztaddr) {
return ZT_PEER_ROLE_PLANET; return ZT_PEER_ROLE_PLANET;
} }
@ -187,32 +206,32 @@ ZT_PeerRole Topology::role(const Address &ztaddr) const
return ZT_PEER_ROLE_LEAF; 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); Mutex::Lock _l(_upstreams_m);
// For roots the only permitted addresses are those defined. This adds just a little // For roots the only permitted addresses are those defined. This adds just a little
// bit of extra security against spoofing, replaying, etc. // bit of extra security against spoofing, replaying, etc.
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { 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) { for (std::vector<World::Root>::const_iterator r(_planet.roots().begin()); r != _planet.roots().end(); ++r) {
if (r->identity.address() == ztaddr) { if (r->identity.address() == ztaddr) {
if (r->stableEndpoints.empty()) { 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)) { if (ipaddr.ipsEqual(*e)) {
return false; return false;
} }
} }
} }
} }
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) {
for(std::vector<World::Root>::const_iterator r(m->roots().begin());r!=m->roots().end();++r) { for (std::vector<World::Root>::const_iterator r(m->roots().begin()); r != m->roots().end(); ++r) {
if (r->identity.address() == ztaddr) { if (r->identity.address() == ztaddr) {
if (r->stableEndpoints.empty()) { 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)) { if (ipaddr.ipsEqual(*e)) {
return false; return false;
} }
@ -226,22 +245,22 @@ bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipa
return false; 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; return false;
} }
Mutex::Lock _l2(_peers_m); Mutex::Lock _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m); Mutex::Lock _l1(_upstreams_m);
World *existing = (World *)0; World* existing = (World*)0;
switch(newWorld.type()) { switch (newWorld.type()) {
case World::TYPE_PLANET: case World::TYPE_PLANET:
existing = &_planet; existing = &_planet;
break; break;
case World::TYPE_MOON: 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()) { if (m->id() == newWorld.id()) {
existing = &(*m); existing = &(*m);
break; break;
@ -255,17 +274,20 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
if (existing) { if (existing) {
if (existing->shouldBeReplacedBy(newWorld)) { if (existing->shouldBeReplacedBy(newWorld)) {
*existing = newWorld; *existing = newWorld;
} else { }
else {
return false; return false;
} }
} else if (newWorld.type() == World::TYPE_MOON) { }
else if (newWorld.type() == World::TYPE_MOON) {
if (alwaysAcceptNew) { if (alwaysAcceptNew) {
_moons.push_back(newWorld); _moons.push_back(newWorld);
existing = &(_moons.back()); 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()) { 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) { if (r->identity.address() == m->second) {
_moonSeeds.erase(m); _moonSeeds.erase(m);
_moons.push_back(newWorld); _moons.push_back(newWorld);
@ -279,73 +301,79 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
} }
} }
} }
if (!existing) { if (! existing) {
return false; return false;
} }
} else { }
else {
return false; return false;
} }
try { try {
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> sbuf; Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> sbuf;
existing->serialize(sbuf,false); existing->serialize(sbuf, false);
uint64_t idtmp[2]; uint64_t idtmp[2];
idtmp[0] = existing->id(); idtmp[0] = existing->id();
idtmp[1] = 0; 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()); RR->node->stateObjectPut(tPtr, (existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON, idtmp, sbuf.data(), sbuf.size());
} catch ( ... ) {} }
catch (...) {
}
_memoizeUpstreams(tPtr); _memoizeUpstreams(tPtr);
return true; 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]; char tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
uint64_t idtmp[2]; uint64_t idtmp[2];
idtmp[0] = id; idtmp[0] = id;
idtmp[1] = 0; 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) { if (n > 0) {
try { try {
World w; World w;
w.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp,(unsigned int)n)); w.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp, (unsigned int)n));
if ((w.type() == World::TYPE_MOON)&&(w.id() == id)) { if ((w.type() == World::TYPE_MOON) && (w.id() == id)) {
addWorld(tPtr,w,true); addWorld(tPtr, w, true);
return; return;
} }
} catch ( ... ) {} }
catch (...) {
}
} }
if (seed) { if (seed) {
Mutex::Lock _l(_upstreams_m); Mutex::Lock _l(_upstreams_m);
if (std::find(_moonSeeds.begin(),_moonSeeds.end(),std::pair<uint64_t,Address>(id,seed)) == _moonSeeds.end()) { 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)); _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 _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m); Mutex::Lock _l1(_upstreams_m);
std::vector<World> nm; 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) { if (m->id() != id) {
nm.push_back(*m); nm.push_back(*m);
} else { }
else {
uint64_t idtmp[2]; uint64_t idtmp[2];
idtmp[0] = id; idtmp[0] = id;
idtmp[1] = 0; idtmp[1] = 0;
RR->node->stateObjectDelete(tPtr,ZT_STATE_OBJECT_MOON,idtmp); RR->node->stateObjectDelete(tPtr, ZT_STATE_OBJECT_MOON, idtmp);
} }
} }
_moons.swap(nm); _moons.swap(nm);
std::vector< std::pair<uint64_t,Address> > cm; 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) { for (std::vector<std::pair<uint64_t, Address> >::const_iterator m(_moonSeeds.begin()); m != _moonSeeds.end(); ++m) {
if (m->first != id) { if (m->first != id) {
cm.push_back(*m); cm.push_back(*m);
} }
@ -355,17 +383,17 @@ void Topology::removeMoon(void *tPtr,const uint64_t id)
_memoizeUpstreams(tPtr); _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 _l1(_peers_m);
Mutex::Lock _l2(_upstreams_m); Mutex::Lock _l2(_upstreams_m);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers); Hashtable<Address, SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0; Address* a = (Address*)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0; SharedPtr<Peer>* p = (SharedPtr<Peer>*)0;
while (i.next(a,p)) { while (i.next(a, p)) {
if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) { if ((! (*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), *a) == _upstreamAddresses.end())) {
_savePeer(tPtr,*p); _savePeer(tPtr, *p);
_peers.erase(*a); _peers.erase(*a);
} }
} }
@ -373,10 +401,10 @@ void Topology::doPeriodicTasks(void *tPtr,int64_t now)
{ {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
Hashtable< Path::HashKey,SharedPtr<Path> >::Iterator i(_paths); Hashtable<Path::HashKey, SharedPtr<Path> >::Iterator i(_paths);
Path::HashKey *k = (Path::HashKey *)0; Path::HashKey* k = (Path::HashKey*)0;
SharedPtr<Path> *p = (SharedPtr<Path> *)0; SharedPtr<Path>* p = (SharedPtr<Path>*)0;
while (i.next(k,p)) { while (i.next(k, p)) {
if (p->references() <= 1) { if (p->references() <= 1) {
_paths.erase(*k); _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 // assumes _upstreams_m and _peers_m are locked
_upstreamAddresses.clear(); _upstreamAddresses.clear();
_amUpstream = false; _amUpstream = false;
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) {
const Identity &id = i->identity; const Identity& id = i->identity;
if (id == RR->identity) { if (id == RR->identity) {
_amUpstream = true; _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()); _upstreamAddresses.push_back(id.address());
SharedPtr<Peer> &hp = _peers[id.address()]; SharedPtr<Peer>& hp = _peers[id.address()];
if (!hp) { if (! hp) {
hp = new Peer(RR,RR->identity,id); hp = new Peer(RR, RR->identity, id);
} }
} }
} }
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) {
for(std::vector<World::Root>::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { for (std::vector<World::Root>::const_iterator i(m->roots().begin()); i != m->roots().end(); ++i) {
if (i->identity == RR->identity) { if (i->identity == RR->identity) {
_amUpstream = true; _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()); _upstreamAddresses.push_back(i->identity.address());
SharedPtr<Peer> &hp = _peers[i->identity.address()]; SharedPtr<Peer>& hp = _peers[i->identity.address()];
if (!hp) { if (! hp) {
hp = new Peer(RR,RR->identity,i->identity); 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 { try {
Buffer<ZT_PEER_MAX_SERIALIZED_STATE_SIZE> buf; 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]; uint64_t tmpid[2];
tmpid[0] = peer->address().toInt(); tmpid[0] = peer->address().toInt();
tmpid[1] = 0; tmpid[1] = 0;
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,tmpid,buf.data(),buf.size()); RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_PEER, tmpid, buf.data(), buf.size());
} catch ( ... ) {} // sanity check, discard invalid entries }
catch (...) {
} // sanity check, discard invalid entries
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

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

File diff suppressed because it is too large Load diff

View file

@ -14,21 +14,20 @@
#ifndef ZT_TRACE_HPP #ifndef ZT_TRACE_HPP
#define ZT_TRACE_HPP #define ZT_TRACE_HPP
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "../include/ZeroTierOne.h" #include "../include/ZeroTierOne.h"
#include "Constants.hpp" #include "Constants.hpp"
#include "SharedPtr.hpp"
#include "Packet.hpp"
#include "Credential.hpp" #include "Credential.hpp"
#include "InetAddress.hpp"
#include "Dictionary.hpp" #include "Dictionary.hpp"
#include "Mutex.hpp"
#include "Hashtable.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 { namespace ZeroTier {
@ -49,20 +48,12 @@ class Capability;
/** /**
* Remote tracing and trace logging handler * Remote tracing and trace logging handler
*/ */
class Trace class Trace {
{ public:
public:
/** /**
* Trace verbosity level * Trace verbosity level
*/ */
enum Level enum Level { LEVEL_NORMAL = 0, LEVEL_VERBOSE = 10, LEVEL_RULES = 15, LEVEL_DEBUG = 20, LEVEL_INSANE = 30 };
{
LEVEL_NORMAL = 0,
LEVEL_VERBOSE = 10,
LEVEL_RULES = 15,
LEVEL_DEBUG = 20,
LEVEL_INSANE = 30
};
/** /**
* Filter rule evaluation result log * Filter rule evaluation result log
@ -73,67 +64,90 @@ public:
* As with four-bit rules an 00 value here means this was not * As with four-bit rules an 00 value here means this was not
* evaluated or was not relevant. * evaluated or was not relevant.
*/ */
class RuleResultLog class RuleResultLog {
{ public:
public: RuleResultLog()
RuleResultLog() {}
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)
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); _l[rn >> 1] |= (thisSetMatches + 1) << ((rn & 1) << 2);
} }
inline void clear() inline void clear()
{ {
memset(_l,0,sizeof(_l)); memset(_l, 0, sizeof(_l));
} }
inline const uint8_t *data() const { return _l; } inline const uint8_t* data() const
inline unsigned int sizeBytes() const { return (ZT_MAX_NETWORK_RULES / 2); } {
return _l;
}
inline unsigned int sizeBytes() const
{
return (ZT_MAX_NETWORK_RULES / 2);
}
private: private:
uint8_t _l[ZT_MAX_NETWORK_RULES / 2]; uint8_t _l[ZT_MAX_NETWORK_RULES / 2];
}; };
Trace(const RuntimeEnvironment *renv) : Trace(const RuntimeEnvironment* renv) : RR(renv), _byNet(8)
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 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 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 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 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 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 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 incomingNetworkAccessDenied(
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* 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 networkFilter(
void *const tPtr, void* const tPtr,
const Network &network, const Network& network,
const RuleResultLog &primaryRuleSetLog, const RuleResultLog& primaryRuleSetLog,
const RuleResultLog *const matchingCapabilityRuleSetLog, const RuleResultLog* const matchingCapabilityRuleSetLog,
const Capability *const matchingCapability, const Capability* const matchingCapability,
const Address &ztSource, const Address& ztSource,
const Address &ztDest, const Address& ztDest,
const MAC &macSource, const MAC& macSource,
const MAC &macDest, const MAC& macDest,
const uint8_t *const frameData, const uint8_t* const frameData,
const unsigned int frameLen, const unsigned int frameLen,
const unsigned int etherType, const unsigned int etherType,
const unsigned int vlanId, const unsigned int vlanId,
@ -141,26 +155,26 @@ public:
const bool inbound, const bool inbound,
const int accept); const int accept);
void credentialRejected(void *const tPtr,const CertificateOfMembership &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 CertificateOfOwnership& c, const char* reason);
void credentialRejected(void *const tPtr,const Capability &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 Tag& c, const char* reason);
void credentialRejected(void *const tPtr,const Revocation &c,const char *reason); void credentialRejected(void* const tPtr, const Revocation& c, const char* reason);
void updateMemoizedSettings(); void updateMemoizedSettings();
private: private:
const RuntimeEnvironment *const RR; const RuntimeEnvironment* const RR;
void _send(void *const tPtr,const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> &d,const Address &dest); 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 _spamToAllNetworks(void* const tPtr, const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE>& d, const Level level);
Address _globalTarget; Address _globalTarget;
Trace::Level _globalLevel; Trace::Level _globalLevel;
Hashtable< uint64_t,std::pair< Address,Trace::Level > > _byNet; Hashtable<uint64_t, std::pair<Address, Trace::Level> > _byNet;
Mutex _byNet_m; Mutex _byNet_m;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #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 "Constants.hpp"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
#include <unistd.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <dirent.h> #include <unistd.h>
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
#ifdef __LINUX__ #ifdef __LINUX__
#include <sys/auxv.h> #include <sys/auxv.h>
@ -36,13 +36,13 @@
#endif #endif
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#include <wincrypt.h>
#include <intrin.h> #include <intrin.h>
#include <wincrypt.h>
#endif #endif
#include "Utils.hpp"
#include "Mutex.hpp" #include "Mutex.hpp"
#include "Salsa20.hpp" #include "Salsa20.hpp"
#include "Utils.hpp"
#ifdef __APPLE__ #ifdef __APPLE__
#include <TargetConditionals.h> #include <TargetConditionals.h>
@ -55,8 +55,8 @@
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
#ifdef __LINUX__ #ifdef __LINUX__
#include <sys/auxv.h>
#include <asm/hwcap.h> #include <asm/hwcap.h>
#include <sys/auxv.h>
#endif #endif
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
@ -87,36 +87,37 @@ static inline long getauxval(int caps)
#define HWCAP_SHA2 0 #define HWCAP_SHA2 0
#endif #endif
#endif // ZT_ARCH_ARM_HAS_NEON #endif // ZT_ARCH_ARM_HAS_NEON
namespace ZeroTier { 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 #ifdef ZT_ARCH_ARM_HAS_NEON
Utils::ARMCapabilities::ARMCapabilities() noexcept Utils::ARMCapabilities::ARMCapabilities() noexcept
{ {
#ifdef __APPLE__ #ifdef __APPLE__
this->aes = true; this->aes = true;
this->crc32 = true; this->crc32 = true;
this->pmull = true; this->pmull = true;
this->sha1 = true; this->sha1 = true;
this->sha2 = true; this->sha2 = true;
#else #else
#ifdef HWCAP2_AES #ifdef HWCAP2_AES
if (sizeof(void *) == 4) { if (sizeof(void*) == 4) {
const long hwcaps2 = getauxval(AT_HWCAP2); const long hwcaps2 = getauxval(AT_HWCAP2);
this->aes = (hwcaps2 & HWCAP2_AES) != 0; this->aes = (hwcaps2 & HWCAP2_AES) != 0;
this->crc32 = (hwcaps2 & HWCAP2_CRC32) != 0; this->crc32 = (hwcaps2 & HWCAP2_CRC32) != 0;
this->pmull = (hwcaps2 & HWCAP2_PMULL) != 0; this->pmull = (hwcaps2 & HWCAP2_PMULL) != 0;
this->sha1 = (hwcaps2 & HWCAP2_SHA1) != 0; this->sha1 = (hwcaps2 & HWCAP2_SHA1) != 0;
this->sha2 = (hwcaps2 & HWCAP2_SHA2) != 0; this->sha2 = (hwcaps2 & HWCAP2_SHA2) != 0;
} else { }
else {
#endif #endif
const long hwcaps = getauxval(AT_HWCAP); const long hwcaps = getauxval(AT_HWCAP);
this->aes = (hwcaps & HWCAP_AES) != 0; this->aes = (hwcaps & HWCAP_AES) != 0;
@ -128,7 +129,7 @@ Utils::ARMCapabilities::ARMCapabilities() noexcept
} }
#endif #endif
#endif // __APPLE__ #endif // __APPLE__
} }
const Utils::ARMCapabilities Utils::ARMCAP; const Utils::ARMCapabilities Utils::ARMCAP;
@ -142,17 +143,13 @@ Utils::CPUIDRegisters::CPUIDRegisters() noexcept
#ifdef __WINDOWS__ #ifdef __WINDOWS__
int regs[4]; int regs[4];
__cpuid(regs,1); __cpuid(regs, 1);
eax = (uint32_t)regs[0]; eax = (uint32_t)regs[0];
ebx = (uint32_t)regs[1]; ebx = (uint32_t)regs[1];
ecx = (uint32_t)regs[2]; ecx = (uint32_t)regs[2];
edx = (uint32_t)regs[3]; edx = (uint32_t)regs[3];
#else #else
__asm__ __volatile__ ( __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1), "c"(0));
"cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(1), "c"(0)
);
#endif #endif
rdrand = ((ecx & (1U << 30U)) != 0); rdrand = ((ecx & (1U << 30U)) != 0);
@ -160,17 +157,13 @@ Utils::CPUIDRegisters::CPUIDRegisters() noexcept
avx = ((ecx & (1U << 25U)) != 0); avx = ((ecx & (1U << 25U)) != 0);
#ifdef __WINDOWS__ #ifdef __WINDOWS__
__cpuid(regs,7); __cpuid(regs, 7);
eax = (uint32_t)regs[0]; eax = (uint32_t)regs[0];
ebx = (uint32_t)regs[1]; ebx = (uint32_t)regs[1];
ecx = (uint32_t)regs[2]; ecx = (uint32_t)regs[2];
edx = (uint32_t)regs[3]; edx = (uint32_t)regs[3];
#else #else
__asm__ __volatile__ ( __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(7), "c"(0));
"cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(7), "c"(0)
);
#endif #endif
vaes = aes && avx && ((ecx & (1U << 9U)) != 0); vaes = aes && avx && ((ecx & (1U << 9U)) != 0);
@ -185,40 +178,43 @@ const Utils::CPUIDRegisters Utils::CPUID;
#endif #endif
// Crazy hack to force memory to be securely zeroed in spite of the best efforts of optimizing compilers. // 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) { while (ptr != end) {
*(ptr++) = (uint8_t)0; *(ptr++) = (uint8_t)0;
} }
} }
static void (*volatile _Utils_doBurn_ptr)(volatile uint8_t *,unsigned int) = _Utils_doBurn; 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); } 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) { if (n == 0) {
return 0; return 0;
} }
unsigned long pos = _Utils_itoa(n / 10,s); unsigned long pos = _Utils_itoa(n / 10, s);
if (pos >= 22) { // sanity check, should be impossible if (pos >= 22) { // sanity check, should be impossible
pos = 22; pos = 22;
} }
s[pos] = '0' + (char)(n % 10); s[pos] = '0' + (char)(n % 10);
return pos + 1; return pos + 1;
} }
char *Utils::decimal(unsigned long n,char s[24]) char* Utils::decimal(unsigned long n, char s[24])
{ {
if (n == 0) { if (n == 0) {
s[0] = '0'; s[0] = '0';
s[1] = (char)0; s[1] = (char)0;
return s; return s;
} }
s[_Utils_itoa(n,s)] = (char)0; s[_Utils_itoa(n, s)] = (char)0;
return s; return s;
} }
void Utils::getSecureRandom(void *buf,unsigned int bytes) void Utils::getSecureRandom(void* buf, unsigned int bytes)
{ {
static Mutex globalLock; static Mutex globalLock;
static Salsa20 s20; 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 * 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 * at almost no cost and with no real downside if the random source is
* good. */ * good. */
if (!s20Initialized) { if (! s20Initialized) {
s20Initialized = true; s20Initialized = true;
uint64_t s20Key[4]; uint64_t s20Key[4];
s20Key[0] = (uint64_t)time(0); // system clock s20Key[0] = (uint64_t)time(0); // system clock
s20Key[1] = (uint64_t)buf; // address of buf s20Key[1] = (uint64_t)buf; // address of buf
s20Key[2] = (uint64_t)s20Key; // address of s20Key[] s20Key[2] = (uint64_t)s20Key; // address of s20Key[]
s20Key[3] = (uint64_t)&s20; // address of s20 s20Key[3] = (uint64_t)&s20; // address of s20
s20.init(s20Key,s20Key); s20.init(s20Key, s20Key);
} }
#ifdef __WINDOWS__ #ifdef __WINDOWS__
static HCRYPTPROV cryptProvider = NULL; 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 (randomPtr >= sizeof(randomBuf)) {
if (cryptProvider == NULL) { if (cryptProvider == NULL) {
if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { 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"); fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n");
exit(1); exit(1);
} }
} }
if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomBuf),(BYTE *)randomBuf)) { if (! CryptGenRandom(cryptProvider, (DWORD)sizeof(randomBuf), (BYTE*)randomBuf)) {
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n"); fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
exit(1); exit(1);
} }
randomPtr = 0; randomPtr = 0;
s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf)); s20.crypt12(randomBuf, randomBuf, sizeof(randomBuf));
s20.init(randomBuf,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; static int devURandomFd = -1;
if (devURandomFd < 0) { if (devURandomFd < 0) {
devURandomFd = ::open("/dev/urandom",O_RDONLY); devURandomFd = ::open("/dev/urandom", O_RDONLY);
if (devURandomFd < 0) { 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); exit(1);
return; return;
} }
} }
for(unsigned int i=0;i<bytes;++i) { for (unsigned int i = 0; i < bytes; ++i) {
if (randomPtr >= sizeof(randomBuf)) { if (randomPtr >= sizeof(randomBuf)) {
for(;;) { for (;;) {
if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) { if ((int)::read(devURandomFd, randomBuf, sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
::close(devURandomFd); ::close(devURandomFd);
devURandomFd = ::open("/dev/urandom",O_RDONLY); devURandomFd = ::open("/dev/urandom", O_RDONLY);
if (devURandomFd < 0) { 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); exit(1);
return; return;
} }
} else { }
else {
break; break;
} }
} }
randomPtr = 0; randomPtr = 0;
s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf)); s20.crypt12(randomBuf, randomBuf, sizeof(randomBuf));
s20.init(randomBuf,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 #ifndef ZT_UTILS_HPP
#define ZT_UTILS_HPP #define ZT_UTILS_HPP
#include <algorithm>
#include <map>
#include <stdexcept>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <string> #include <string>
#include <stdexcept> #include <time.h>
#include <vector> #include <vector>
#include <map>
#include <algorithm>
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
#include <sys/endian.h> #include <sys/endian.h>
@ -34,15 +33,9 @@
#if __BYTE_ORDER == __LITTLE_ENDIAN #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_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U)))
#define ZT_CONST_TO_BE_UINT64(x) ( \ #define ZT_CONST_TO_BE_UINT64(x) \
(((uint64_t)(x) & 0x00000000000000ffULL) << 56U) | \ ((((uint64_t)(x) & 0x00000000000000ffULL) << 56U) | (((uint64_t)(x) & 0x000000000000ff00ULL) << 40U) | (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24U) | (((uint64_t)(x) & 0x00000000ff000000ULL) << 8U) \
(((uint64_t)(x) & 0x000000000000ff00ULL) << 40U) | \ | (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8U) | (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24U) | (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40U) | (((uint64_t)(x) & 0xff00000000000000ULL) >> 56U))
(((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 #else
#define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)(x)) #define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)(x))
#define ZT_CONST_TO_BE_UINT64(x) ((uint64_t)(x)) #define ZT_CONST_TO_BE_UINT64(x) ((uint64_t)(x))
@ -58,14 +51,12 @@ namespace ZeroTier {
/** /**
* Miscellaneous utility functions and global constants * Miscellaneous utility functions and global constants
*/ */
class Utils class Utils {
{ public:
public:
static const uint64_t ZERO256[4]; static const uint64_t ZERO256[4];
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
struct ARMCapabilities struct ARMCapabilities {
{
ARMCapabilities() noexcept; ARMCapabilities() noexcept;
bool aes; bool aes;
@ -78,15 +69,14 @@ public:
#endif #endif
#ifdef ZT_ARCH_X64 #ifdef ZT_ARCH_X64
struct CPUIDRegisters struct CPUIDRegisters {
{
CPUIDRegisters() noexcept; CPUIDRegisters() noexcept;
bool rdrand; bool rdrand;
bool aes; bool aes;
bool avx; bool avx;
bool vaes; // implies AVX bool vaes; // implies AVX
bool vpclmulqdq; // implies AVX bool vpclmulqdq; // implies AVX
bool avx2; bool avx2;
bool avx512f; bool avx512f;
bool sha; bool sha;
@ -97,7 +87,7 @@ public:
/** /**
* Compute the log2 (most significant bit set) of a 32-bit integer * Compute the log2 (most significant bit set) of a 32-bit integer
* *
* @param v Integer to compute * @param v Integer to compute
* @return log2 or 0 if v is 0 * @return log2 or 0 if v is 0
*/ */
@ -126,11 +116,11 @@ public:
* @param len Length of strings * @param len Length of strings
* @return True if strings are equal * @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; uint8_t diff = 0;
for(unsigned int i=0;i<len;++i) { for (unsigned int i = 0; i < len; ++i) {
diff |= ( (reinterpret_cast<const uint8_t *>(a))[i] ^ (reinterpret_cast<const uint8_t *>(b))[i] ); diff |= ((reinterpret_cast<const uint8_t*>(a))[i] ^ (reinterpret_cast<const uint8_t*>(b))[i]);
} }
return (diff == 0); return (diff == 0);
} }
@ -138,16 +128,16 @@ public:
/** /**
* Securely zero memory, avoiding compiler optimizations and such * 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 n Number to convert
* @param s Buffer, at least 24 bytes in size * @param s Buffer, at least 24 bytes in size
* @return String containing 'n' in base 10 form * @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[0] = HEXCHARS[(i >> 60) & 0xf];
s[1] = HEXCHARS[(i >> 56) & 0xf]; s[1] = HEXCHARS[(i >> 56) & 0xf];
@ -169,7 +159,7 @@ public:
return s; 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[0] = HEXCHARS[(i >> 36) & 0xf];
s[1] = HEXCHARS[(i >> 32) & 0xf]; s[1] = HEXCHARS[(i >> 32) & 0xf];
@ -185,7 +175,7 @@ public:
return s; 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[0] = HEXCHARS[(i >> 28) & 0xf];
s[1] = HEXCHARS[(i >> 24) & 0xf]; s[1] = HEXCHARS[(i >> 24) & 0xf];
@ -199,7 +189,7 @@ public:
return s; 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[0] = HEXCHARS[(i >> 12) & 0xf];
s[1] = HEXCHARS[(i >> 8) & 0xf]; s[1] = HEXCHARS[(i >> 8) & 0xf];
@ -209,7 +199,7 @@ public:
return s; 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[0] = HEXCHARS[(i >> 4) & 0xf];
s[1] = HEXCHARS[i & 0xf]; s[1] = HEXCHARS[i & 0xf];
@ -217,11 +207,11 @@ public:
return s; 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; char* const save = s;
for(unsigned int i=0;i<l;++i) { for (unsigned int i = 0; i < l; ++i) {
const unsigned int b = reinterpret_cast<const uint8_t *>(d)[i]; const unsigned int b = reinterpret_cast<const uint8_t*>(d)[i];
*(s++) = HEXCHARS[b >> 4]; *(s++) = HEXCHARS[b >> 4];
*(s++) = HEXCHARS[b & 0xf]; *(s++) = HEXCHARS[b & 0xf];
} }
@ -229,83 +219,91 @@ public:
return save; 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; unsigned int l = 0;
while (l < buflen) { while (l < buflen) {
uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++)); uint8_t hc = *(reinterpret_cast<const uint8_t*>(h++));
if (!hc) { if (! hc) {
break; break;
} }
uint8_t c = 0; uint8_t c = 0;
if ((hc >= 48)&&(hc <= 57)) { // 0..9 if ((hc >= 48) && (hc <= 57)) { // 0..9
c = hc - 48; c = hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) { // a..f }
else if ((hc >= 97) && (hc <= 102)) { // a..f
c = hc - 87; c = hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) { // A..F }
else if ((hc >= 65) && (hc <= 70)) { // A..F
c = hc - 55; c = hc - 55;
} }
hc = *(reinterpret_cast<const uint8_t *>(h++)); hc = *(reinterpret_cast<const uint8_t*>(h++));
if (!hc) { if (! hc) {
break; break;
} }
c <<= 4; c <<= 4;
if ((hc >= 48)&&(hc <= 57)) { if ((hc >= 48) && (hc <= 57)) {
c |= hc - 48; c |= hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) { }
else if ((hc >= 97) && (hc <= 102)) {
c |= hc - 87; c |= hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) { }
else if ((hc >= 65) && (hc <= 70)) {
c |= hc - 55; c |= hc - 55;
} }
reinterpret_cast<uint8_t *>(buf)[l++] = c; reinterpret_cast<uint8_t*>(buf)[l++] = c;
} }
return l; 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; unsigned int l = 0;
const char *hend = h + hlen; const char* hend = h + hlen;
while (l < buflen) { while (l < buflen) {
if (h == hend) { if (h == hend) {
break; break;
} }
uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++)); uint8_t hc = *(reinterpret_cast<const uint8_t*>(h++));
if (!hc) { if (! hc) {
break; break;
} }
uint8_t c = 0; uint8_t c = 0;
if ((hc >= 48)&&(hc <= 57)) { if ((hc >= 48) && (hc <= 57)) {
c = hc - 48; c = hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) { }
else if ((hc >= 97) && (hc <= 102)) {
c = hc - 87; c = hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) { }
else if ((hc >= 65) && (hc <= 70)) {
c = hc - 55; c = hc - 55;
} }
if (h == hend) { if (h == hend) {
break; break;
} }
hc = *(reinterpret_cast<const uint8_t *>(h++)); hc = *(reinterpret_cast<const uint8_t*>(h++));
if (!hc) { if (! hc) {
break; break;
} }
c <<= 4; c <<= 4;
if ((hc >= 48)&&(hc <= 57)) { if ((hc >= 48) && (hc <= 57)) {
c |= hc - 48; c |= hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) { }
else if ((hc >= 97) && (hc <= 102)) {
c |= hc - 87; c |= hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) { }
else if ((hc >= 65) && (hc <= 70)) {
c |= hc - 55; c |= hc - 55;
} }
reinterpret_cast<uint8_t *>(buf)[l++] = c; reinterpret_cast<uint8_t*>(buf)[l++] = c;
} }
return l; return l;
} }
@ -327,7 +325,7 @@ public:
* @param buf Buffer to fill * @param buf Buffer to fill
* @param bytes Number of random bytes to generate * @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) * Tokenize a string (alias for strtok_r or strtok_s depending on platform)
@ -336,54 +334,81 @@ public:
* @param delim Delimiters * @param delim Delimiters
* @param saveptr Pointer to a char * for temporary reentrant storage * @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__ #ifdef __WINDOWS__
return strtok_s(str,delim,saveptr); return strtok_s(str, delim, saveptr);
#else #else
return strtok_r(str,delim,saveptr); return strtok_r(str, delim, saveptr);
#endif #endif
} }
static inline unsigned int strToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,10); } static inline unsigned int strToUInt(const char* s)
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); } return (unsigned int)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 int strToInt(const char* s)
static inline unsigned long long strToU64(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__ #ifdef __WINDOWS__
return (unsigned long long)_strtoui64(s,(char **)0,10); return (unsigned long long)_strtoui64(s, (char**)0, 10);
#else #else
return strtoull(s,(char **)0,10); return strtoull(s, (char**)0, 10);
#endif #endif
} }
static inline long long strTo64(const char *s) static inline long long strTo64(const char* s)
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
return (long long)_strtoi64(s,(char **)0,10); return (long long)_strtoi64(s, (char**)0, 10);
#else #else
return strtoll(s,(char **)0,10); return strtoll(s, (char**)0, 10);
#endif #endif
} }
static inline unsigned int hexStrToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,16); } static inline unsigned int hexStrToUInt(const char* s)
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); } return (unsigned int)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 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__ #ifdef __WINDOWS__
return (unsigned long long)_strtoui64(s,(char **)0,16); return (unsigned long long)_strtoui64(s, (char**)0, 16);
#else #else
return strtoull(s,(char **)0,16); return strtoull(s, (char**)0, 16);
#endif #endif
} }
static inline long long hexStrTo64(const char *s) static inline long long hexStrTo64(const char* s)
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
return (long long)_strtoi64(s,(char **)0,16); return (long long)_strtoi64(s, (char**)0, 16);
#else #else
return strtoll(s,(char **)0,16); return strtoll(s, (char**)0, 16);
#endif #endif
} }
@ -398,16 +423,16 @@ public:
* @param src Source string (if NULL, dest will receive a zero-length string and true is returned) * @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) * @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) { if (! len) {
return false; // sanity check return false; // sanity check
} }
if (!src) { if (! src) {
*dest = (char)0; *dest = (char)0;
return true; return true;
} }
char *end = dest + len; char* end = dest + len;
while ((*dest++ = *src++)) { while ((*dest++ = *src++)) {
if (dest == end) { if (dest == end) {
*(--dest) = (char)0; *(--dest) = (char)0;
@ -438,10 +463,10 @@ public:
*/ */
static inline uint64_t countBits(uint64_t v) static inline uint64_t countBits(uint64_t v)
{ {
v = v - ((v >> 1) & (uint64_t)~(uint64_t)0/3); 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 & (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; v = (v + (v >> 4)) & (uint64_t)~(uint64_t)0 / 255 * 15;
return (uint64_t)(v * ((uint64_t)~(uint64_t)0/255)) >> 56; return (uint64_t)(v * ((uint64_t)~(uint64_t)0 / 255)) >> 56;
} }
/** /**
@ -451,10 +476,10 @@ public:
* @param len Length of memory * @param len Length of memory
* @return True if memory is all zero * @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) { for (unsigned int i = 0; i < len; ++i) {
if (((const unsigned char *)p)[i]) { if (((const unsigned char*)p)[i]) {
return false; return false;
} }
} }
@ -469,24 +494,17 @@ public:
*/ */
static ZT_INLINE uint64_t swapBytes(const uint64_t n) noexcept static ZT_INLINE uint64_t swapBytes(const uint64_t n) noexcept
{ {
#ifdef __GNUC__ #ifdef __GNUC__
return __builtin_bswap64(n); return __builtin_bswap64(n);
#else #else
#ifdef _MSC_VER #ifdef _MSC_VER
return (uint64_t)_byteswap_uint64((unsigned __int64)n); return (uint64_t)_byteswap_uint64((unsigned __int64)n);
#else #else
return ( return (
((n & 0x00000000000000ffULL) << 56) | ((n & 0x00000000000000ffULL) << 56) | ((n & 0x000000000000ff00ULL) << 40) | ((n & 0x0000000000ff0000ULL) << 24) | ((n & 0x00000000ff000000ULL) << 8) | ((n & 0x000000ff00000000ULL) >> 8) | ((n & 0x0000ff0000000000ULL) >> 24)
((n & 0x000000000000ff00ULL) << 40) | | ((n & 0x00ff000000000000ULL) >> 40) | ((n & 0xff00000000000000ULL) >> 56));
((n & 0x0000000000ff0000ULL) << 24) | #endif
((n & 0x00000000ff000000ULL) << 8) | #endif
((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 static ZT_INLINE uint32_t swapBytes(const uint32_t n) noexcept
{ {
#if defined(__GNUC__) #if defined(__GNUC__)
return __builtin_bswap32(n); return __builtin_bswap32(n);
#else #else
#ifdef _MSC_VER #ifdef _MSC_VER
return (uint32_t)_byteswap_ulong((unsigned long)n); return (uint32_t)_byteswap_ulong((unsigned long)n);
#else #else
return htonl(n); return htonl(n);
#endif #endif
#endif #endif
} }
/** /**
@ -516,122 +534,119 @@ public:
*/ */
static ZT_INLINE uint16_t swapBytes(const uint16_t n) noexcept static ZT_INLINE uint16_t swapBytes(const uint16_t n) noexcept
{ {
#if defined(__GNUC__) #if defined(__GNUC__)
return __builtin_bswap16(n); return __builtin_bswap16(n);
#else #else
#ifdef _MSC_VER #ifdef _MSC_VER
return (uint16_t)_byteswap_ushort((unsigned short)n); return (uint16_t)_byteswap_ushort((unsigned short)n);
#else #else
return htons(n); return htons(n);
#endif #endif
#endif #endif
} }
// These are helper adapters to load and swap integer types special cased by size // These are helper adapters to load and swap integer types special cased by size
// to work with all typedef'd variants, signed/unsigned, etc. // to work with all typedef'd variants, signed/unsigned, etc.
template< typename I, unsigned int S > template <typename I, unsigned int S> class _swap_bytes_bysize;
class _swap_bytes_bysize;
template< typename I > template <typename I> class _swap_bytes_bysize<I, 1> {
class _swap_bytes_bysize< I, 1 > public:
{
public:
static ZT_INLINE I s(const I n) noexcept static ZT_INLINE I s(const I n) noexcept
{ return n; } {
return n;
}
}; };
template< typename I > template <typename I> class _swap_bytes_bysize<I, 2> {
class _swap_bytes_bysize< I, 2 > public:
{
public:
static ZT_INLINE I s(const I n) noexcept static ZT_INLINE I s(const I n) noexcept
{ return (I)swapBytes((uint16_t)n); } {
return (I)swapBytes((uint16_t)n);
}
}; };
template< typename I > template <typename I> class _swap_bytes_bysize<I, 4> {
class _swap_bytes_bysize< I, 4 > public:
{
public:
static ZT_INLINE I s(const I n) noexcept static ZT_INLINE I s(const I n) noexcept
{ return (I)swapBytes((uint32_t)n); } {
return (I)swapBytes((uint32_t)n);
}
}; };
template< typename I > template <typename I> class _swap_bytes_bysize<I, 8> {
class _swap_bytes_bysize< I, 8 > public:
{
public:
static ZT_INLINE I s(const I n) noexcept 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 > template <typename I, unsigned int S> class _load_be_bysize;
class _load_be_bysize;
template< typename I > template <typename I> class _load_be_bysize<I, 1> {
class _load_be_bysize< I, 1 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return p[0];
{ return p[0]; } }
}; };
template< typename I > template <typename I> class _load_be_bysize<I, 2> {
class _load_be_bysize< I, 2 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]);
{ return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]); } }
}; };
template< typename I > template <typename I> class _load_be_bysize<I, 4> {
class _load_be_bysize< I, 4 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
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]);
{ return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]); } }
}; };
template< typename I > template <typename I> class _load_be_bysize<I, 8> {
class _load_be_bysize< I, 8 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
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]);
{ 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 > template <typename I, unsigned int S> class _load_le_bysize;
class _load_le_bysize;
template< typename I > template <typename I> class _load_le_bysize<I, 1> {
class _load_le_bysize< I, 1 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return p[0];
{ return p[0]; } }
}; };
template< typename I > template <typename I> class _load_le_bysize<I, 2> {
class _load_le_bysize< I, 2 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U));
{ return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U)); } }
}; };
template< typename I > template <typename I> class _load_le_bysize<I, 4> {
class _load_le_bysize< I, 4 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
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));
{ return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U)); } }
}; };
template< typename I > template <typename I> class _load_le_bysize<I, 8> {
class _load_le_bysize< I, 8 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
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);
{ 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 * @param n Value to convert
* @return Value in big-endian order * @return Value in big-endian order
*/ */
template< typename I > template <typename I> static ZT_INLINE I hton(const I n) noexcept
static ZT_INLINE I hton(const I n) noexcept
{ {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
return _swap_bytes_bysize< I, sizeof(I) >::s(n); return _swap_bytes_bysize<I, sizeof(I)>::s(n);
#else #else
return n; return n;
#endif #endif
} }
/** /**
@ -658,14 +672,13 @@ public:
* @param n Value to convert * @param n Value to convert
* @return Value in host byte order * @return Value in host byte order
*/ */
template< typename I > template <typename I> static ZT_INLINE I ntoh(const I n) noexcept
static ZT_INLINE I ntoh(const I n) noexcept
{ {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
return _swap_bytes_bysize< I, sizeof(I) >::s(n); return _swap_bytes_bysize<I, sizeof(I)>::s(n);
#else #else
return n; return n;
#endif #endif
} }
/** /**
@ -675,18 +688,17 @@ public:
* @param p Byte stream, must be at least sizeof(I) in size * @param p Byte stream, must be at least sizeof(I) in size
* @return Loaded raw integer * @return Loaded raw integer
*/ */
template< typename I > template <typename I> static ZT_INLINE I loadMachineEndian(const void* const p) noexcept
static ZT_INLINE I loadMachineEndian(const void *const p) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
I tmp; I tmp;
for(int i=0;i<(int)sizeof(I);++i) { for (int i = 0; i < (int)sizeof(I); ++i) {
reinterpret_cast<uint8_t *>(&tmp)[i] = reinterpret_cast<const uint8_t *>(p)[i]; reinterpret_cast<uint8_t*>(&tmp)[i] = reinterpret_cast<const uint8_t*>(p)[i];
} }
return tmp; return tmp;
#else #else
return *reinterpret_cast<const I *>(p); return *reinterpret_cast<const I*>(p);
#endif #endif
} }
/** /**
@ -696,16 +708,15 @@ public:
* @param p Byte array (must be at least sizeof(I)) * @param p Byte array (must be at least sizeof(I))
* @param i Integer to store * @param i Integer to store
*/ */
template< typename I > template <typename I> static ZT_INLINE void storeMachineEndian(void* const p, const I i) noexcept
static ZT_INLINE void storeMachineEndian(void *const p, const I i) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
for(unsigned int k=0;k<sizeof(I);++k) { for (unsigned int k = 0; k < sizeof(I); ++k) {
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[k]; reinterpret_cast<uint8_t*>(p)[k] = reinterpret_cast<const uint8_t*>(&i)[k];
} }
#else #else
*reinterpret_cast<I *>(p) = i; *reinterpret_cast<I*>(p) = i;
#endif #endif
} }
/** /**
@ -715,14 +726,13 @@ public:
* @param p Byte stream, must be at least sizeof(I) in size * @param p Byte stream, must be at least sizeof(I) in size
* @return Decoded integer * @return Decoded integer
*/ */
template< typename I > template <typename I> static ZT_INLINE I loadBigEndian(const void* const p) noexcept
static ZT_INLINE I loadBigEndian(const void *const p) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return _load_be_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p)); return _load_be_bysize<I, sizeof(I)>::l(reinterpret_cast<const uint8_t*>(p));
#else #else
return ntoh(*reinterpret_cast<const I *>(p)); return ntoh(*reinterpret_cast<const I*>(p));
#endif #endif
} }
/** /**
@ -732,14 +742,13 @@ public:
* @param p Byte stream to write (must be at least sizeof(I)) * @param p Byte stream to write (must be at least sizeof(I))
* #param i Integer to write * #param i Integer to write
*/ */
template< typename I > template <typename I> static ZT_INLINE void storeBigEndian(void* const p, I i) noexcept
static ZT_INLINE void storeBigEndian(void *const p, I i) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
storeMachineEndian(p,hton(i)); storeMachineEndian(p, hton(i));
#else #else
*reinterpret_cast<I *>(p) = hton(i); *reinterpret_cast<I*>(p) = hton(i);
#endif #endif
} }
/** /**
@ -749,14 +758,13 @@ public:
* @param p Byte stream, must be at least sizeof(I) in size * @param p Byte stream, must be at least sizeof(I) in size
* @return Decoded integer * @return Decoded integer
*/ */
template< typename I > template <typename I> static ZT_INLINE I loadLittleEndian(const void* const p) noexcept
static ZT_INLINE I loadLittleEndian(const void *const p) noexcept
{ {
#if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS) #if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
return _load_le_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p)); return _load_le_bysize<I, sizeof(I)>::l(reinterpret_cast<const uint8_t*>(p));
#else #else
return *reinterpret_cast<const I *>(p); return *reinterpret_cast<const I*>(p);
#endif #endif
} }
/** /**
@ -766,18 +774,17 @@ public:
* @param p Byte stream to write (must be at least sizeof(I)) * @param p Byte stream to write (must be at least sizeof(I))
* #param i Integer to write * #param i Integer to write
*/ */
template< typename I > template <typename I> static ZT_INLINE void storeLittleEndian(void* const p, const I i) noexcept
static ZT_INLINE void storeLittleEndian(void *const p, const I i) noexcept
{ {
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
storeMachineEndian(p,_swap_bytes_bysize<I,sizeof(I)>::s(i)); storeMachineEndian(p, _swap_bytes_bysize<I, sizeof(I)>::s(i));
#else #else
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
storeMachineEndian(p,i); storeMachineEndian(p, i);
#else #else
*reinterpret_cast<I *>(p) = i; *reinterpret_cast<I*>(p) = i;
#endif #endif
#endif #endif
} }
/** /**
@ -787,15 +794,14 @@ public:
* @param dest Destination memory * @param dest Destination memory
* @param src Source memory * @param src Source memory
*/ */
template< unsigned long L > template <unsigned long L> static ZT_INLINE void copy(void* dest, const void* src) noexcept
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; uintptr_t l = L;
__asm__ __volatile__ ("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest) :: "memory"); __asm__ __volatile__("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest)::"memory");
#else #else
memcpy(dest, src, L); memcpy(dest, src, L);
#endif #endif
} }
/** /**
@ -805,13 +811,13 @@ public:
* @param src Source memory * @param src Source memory
* @param len Bytes to copy * @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__) #if defined(ZT_ARCH_X64) && defined(__GNUC__)
__asm__ __volatile__ ("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest) :: "memory"); __asm__ __volatile__("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest)::"memory");
#else #else
memcpy(dest, src, len); memcpy(dest, src, len);
#endif #endif
} }
/** /**
@ -820,15 +826,14 @@ public:
* @tparam L Size in bytes * @tparam L Size in bytes
* @param dest Memory to zero * @param dest Memory to zero
*/ */
template< unsigned long L > template <unsigned long L> static ZT_INLINE void zero(void* dest) noexcept
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; uintptr_t l = L;
__asm__ __volatile__ ("cld ; rep stosb" :"+c" (l), "+D" (dest) : "a" (0) : "memory"); __asm__ __volatile__("cld ; rep stosb" : "+c"(l), "+D"(dest) : "a"(0) : "memory");
#else #else
memset(dest, 0, L); memset(dest, 0, L);
#endif #endif
} }
/** /**
@ -837,13 +842,13 @@ public:
* @param dest Memory to zero * @param dest Memory to zero
* @param len Size in bytes * @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__) #if defined(ZT_ARCH_X64) && defined(__GNUC__)
__asm__ __volatile__ ("cld ; rep stosb" :"+c" (len), "+D" (dest) : "a" (0) : "memory"); __asm__ __volatile__("cld ; rep stosb" : "+c"(len), "+D"(dest) : "a"(0) : "memory");
#else #else
memset(dest, 0, len); memset(dest, 0, len);
#endif #endif
} }
/** /**
@ -855,7 +860,7 @@ public:
* Remove `-` and `:` from a MAC address (in-place). * Remove `-` and `:` from a MAC address (in-place).
* *
* @param mac The MAC address * @param mac The MAC address
*/ */
static inline void cleanMac(std::string& mac) static inline void cleanMac(std::string& mac)
{ {
auto start = mac.begin(); auto start = mac.begin();
@ -865,6 +870,6 @@ public:
} }
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -14,14 +14,14 @@
#ifndef ZT_WORLD_HPP #ifndef ZT_WORLD_HPP
#define ZT_WORLD_HPP #define ZT_WORLD_HPP
#include <vector>
#include <string>
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "Identity.hpp"
#include "Buffer.hpp" #include "Buffer.hpp"
#include "C25519.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) * 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 for Mars and nearby space is defined but not yet used, and a test
* world ID is provided for testing purposes. * world ID is provided for testing purposes.
*/ */
class World class World {
{ public:
public:
/** /**
* World type -- do not change IDs * World type -- do not change IDs
*/ */
enum Type enum Type {
{
TYPE_NULL = 0, TYPE_NULL = 0,
TYPE_PLANET = 1, // Planets, of which there is currently one (Earth) TYPE_PLANET = 1, // Planets, of which there is currently one (Earth)
TYPE_MOON = 127 // Moons, which are user-created and many TYPE_MOON = 127 // Moons, which are user-created and many
}; };
/** /**
* Upstream server definition in world/moon * Upstream server definition in world/moon
*/ */
struct Root struct Root {
{
Identity identity; Identity identity;
std::vector<InetAddress> stableEndpoints; 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
inline bool operator!=(const Root &r) const { return (!(*this == r)); } {
inline bool operator<(const Root &r) const { return (identity < r.identity); } // for sorting 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 * Construct an empty / null World
*/ */
World() : World() : _id(0), _ts(0), _type(TYPE_NULL)
_id(0), {
_ts(0), }
_type(TYPE_NULL) {}
/** /**
* @return Root servers for this world and their stable endpoints * @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 * @return World type: planet or moon
*/ */
inline Type type() const { return _type; } inline Type type() const
{
return _type;
}
/** /**
* @return World unique identifier * @return World unique identifier
*/ */
inline uint64_t id() const { return _id; } inline uint64_t id() const
{
return _id;
}
/** /**
* @return World definition timestamp * @return World definition timestamp
*/ */
inline uint64_t timestamp() const { return _ts; } inline uint64_t timestamp() const
{
return _ts;
}
/** /**
* @return C25519 signature * @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 * @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 * Check whether a world update should replace this one
@ -146,15 +169,15 @@ public:
* @param update Candidate update * @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) * @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; 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; Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
update.serialize(tmp,true); update.serialize(tmp, true);
return C25519::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature); return C25519::verify(_updatesMustBeSignedBy, tmp.data(), tmp.size(), update._signature);
} }
return false; return false;
} }
@ -162,10 +185,12 @@ public:
/** /**
* @return True if this World is non-empty * @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> template <unsigned int C> inline void serialize(Buffer<C>& b, bool forSign = false) const
inline void serialize(Buffer<C> &b,bool forSign = false) const
{ {
if (forSign) { if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -174,20 +199,20 @@ public:
b.append((uint8_t)_type); b.append((uint8_t)_type);
b.append((uint64_t)_id); b.append((uint64_t)_id);
b.append((uint64_t)_ts); b.append((uint64_t)_ts);
b.append(_updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN); b.append(_updatesMustBeSignedBy.data, ZT_C25519_PUBLIC_KEY_LEN);
if (!forSign) { if (! forSign) {
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); b.append(_signature.data, ZT_C25519_SIGNATURE_LEN);
} }
b.append((uint8_t)_roots.size()); 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); r->identity.serialize(b);
b.append((uint8_t)r->stableEndpoints.size()); 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); ep->serialize(b);
} }
} }
if (_type == TYPE_MOON) { 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) { if (forSign) {
@ -195,15 +220,14 @@ public:
} }
} }
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{ {
unsigned int p = startAt; unsigned int p = startAt;
_roots.clear(); _roots.clear();
switch((Type)b[p++]) { switch ((Type)b[p++]) {
case TYPE_NULL: // shouldn't ever really happen in serialized data but it's not invalid case TYPE_NULL: // shouldn't ever really happen in serialized data but it's not invalid
_type = TYPE_NULL; _type = TYPE_NULL;
break; break;
case TYPE_PLANET: case TYPE_PLANET:
@ -220,25 +244,25 @@ public:
p += 8; p += 8;
_ts = b.template at<uint64_t>(p); _ts = b.template at<uint64_t>(p);
p += 8; 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; 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; p += ZT_C25519_SIGNATURE_LEN;
const unsigned int numRoots = (unsigned int)b[p++]; const unsigned int numRoots = (unsigned int)b[p++];
if (numRoots > ZT_WORLD_MAX_ROOTS) { if (numRoots > ZT_WORLD_MAX_ROOTS) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; 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()); _roots.push_back(Root());
Root &r = _roots.back(); Root& r = _roots.back();
p += r.identity.deserialize(b,p); p += r.identity.deserialize(b, p);
unsigned int numStableEndpoints = b[p++]; unsigned int numStableEndpoints = b[p++];
if (numStableEndpoints > ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT) { if (numStableEndpoints > ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; 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()); r.stableEndpoints.push_back(InetAddress());
p += r.stableEndpoints.back().deserialize(b,p); p += r.stableEndpoints.back().deserialize(b, p);
} }
} }
if (_type == TYPE_MOON) { if (_type == TYPE_MOON) {
@ -248,8 +272,16 @@ public:
return (p - startAt); 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
inline bool operator!=(const World &w) const { return (!(*this == w)); } {
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 * 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) * @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 * @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; World w;
w._id = id; w._id = id;
@ -272,13 +304,13 @@ public:
w._roots = roots; w._roots = roots;
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp; Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
w.serialize(tmp,true); w.serialize(tmp, true);
w._signature = C25519::sign(signWith,tmp.data(),tmp.size()); w._signature = C25519::sign(signWith, tmp.data(), tmp.size());
return w; return w;
} }
protected: protected:
uint64_t _id; uint64_t _id;
uint64_t _ts; uint64_t _ts;
Type _type; Type _type;
@ -287,6 +319,6 @@ protected:
std::vector<Root> _roots; std::vector<Root> _roots;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

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

View file

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

View file

@ -11,81 +11,78 @@
*/ */
/****/ /****/
#include <stdint.h> #include "BSDEthernetTap.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h> #include "../node/Constants.hpp"
#include <signal.h> #include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
#include "OSUtils.hpp"
#include <fcntl.h> #include <algorithm>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/cdefs.h>
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <net/if.h> #include <errno.h>
#include <fcntl.h>
#include <ifaddrs.h> #include <ifaddrs.h>
#include <map>
#include <net/if.h>
#include <net/if_arp.h> #include <net/if_arp.h>
#include <net/if_dl.h> #include <net/if_dl.h>
#include <net/if_media.h> #include <net/if_media.h>
#include <net/route.h> #include <net/route.h>
#include <netinet/in.h>
#include <pthread_np.h> #include <pthread_np.h>
#include <sched.h> #include <sched.h>
#include <string>
#include <map>
#include <set> #include <set>
#include <algorithm> #include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <utility> #include <utility>
#include "../node/Constants.hpp"
#include "../node/Utils.hpp"
#include "../node/Mutex.hpp"
#include "OSUtils.hpp"
#include "BSDEthernetTap.hpp"
#define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv" #define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv"
#define ZT_TAP_BUF_SIZE (1024 * 16) #define ZT_TAP_BUF_SIZE (1024 * 16)
// ff:ff:ff:ff:ff:ff with no ADI // ff:ff:ff:ff:ff:ff with no ADI
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0);
namespace ZeroTier { namespace ZeroTier {
BSDEthernetTap::BSDEthernetTap( BSDEthernetTap::BSDEthernetTap(
const char *homePath, const char* homePath,
unsigned int concurrency, unsigned int concurrency,
bool pinning, bool pinning,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg) : void* arg)
_handler(handler), : _handler(handler)
_concurrency(concurrency), , _concurrency(concurrency)
_pinning(pinning), , _pinning(pinning)
_arg(arg), , _arg(arg)
_nwid(nwid), , _nwid(nwid)
_mtu(mtu), , _mtu(mtu)
_metric(metric), , _metric(metric)
_fd(0), , _fd(0)
_enabled(true), , _enabled(true)
_lastIfAddrsUpdate(0) , _lastIfAddrsUpdate(0)
{ {
static Mutex globalTapCreateLock; static Mutex globalTapCreateLock;
char devpath[64],ethaddr[64],mtustr[32],metstr[32],tmpdevname[32]; char devpath[64], ethaddr[64], mtustr[32], metstr[32], tmpdevname[32];
Mutex::Lock _gl(globalTapCreateLock); Mutex::Lock _gl(globalTapCreateLock);
@ -108,43 +105,51 @@ BSDEthernetTap::BSDEthernetTap(
_dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]); _dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]);
std::vector<std::string> devFiles(OSUtils::listDirectory("/dev")); std::vector<std::string> devFiles(OSUtils::listDirectory("/dev"));
for(int i=9993;i<(9993+128);++i) { for (int i = 9993; i < (9993 + 128); ++i) {
OSUtils::ztsnprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); OSUtils::ztsnprintf(tmpdevname, sizeof(tmpdevname), "tap%d", i);
OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); OSUtils::ztsnprintf(devpath, sizeof(devpath), "/dev/%s", tmpdevname);
if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) { if (std::find(devFiles.begin(), devFiles.end(), std::string(tmpdevname)) == devFiles.end()) {
long cpid = (long)vfork(); long cpid = (long)vfork();
if (cpid == 0) { if (cpid == 0) {
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s create" ZT_EOL_S, tmpdevname); fprintf(stderr, "DEBUG: ifconfig %s create" ZT_EOL_S, tmpdevname);
#endif #endif
::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", tmpdevname, "create", (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
} else throw std::runtime_error("fork() failed"); }
else
throw std::runtime_error("fork() failed");
struct stat stattmp; struct stat stattmp;
if (!stat(devpath,&stattmp)) { if (! stat(devpath, &stattmp)) {
cpid = (long)vfork(); cpid = (long)vfork();
if (cpid == 0) { if (cpid == 0) {
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s name %s" ZT_EOL_S, tmpdevname, _dev.c_str()); fprintf(stderr, "DEBUG: ifconfig %s name %s" ZT_EOL_S, tmpdevname, _dev.c_str());
#endif #endif
::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"name",_dev.c_str(),(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", tmpdevname, "name", _dev.c_str(), (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
if (exitcode) if (exitcode)
throw std::runtime_error("ifconfig rename operation failed"); throw std::runtime_error("ifconfig rename operation failed");
} else throw std::runtime_error("fork() failed"); }
else
throw std::runtime_error("fork() failed");
_fd = ::open(devpath,O_RDWR); _fd = ::open(devpath, O_RDWR);
if (_fd > 0) if (_fd > 0)
break; break;
else throw std::runtime_error("unable to open created tap device"); else
} else { throw std::runtime_error("unable to open created tap device");
}
else {
throw std::runtime_error("cannot find /dev node for newly created tap device"); throw std::runtime_error("cannot find /dev node for newly created tap device");
} }
} }
@ -152,10 +157,10 @@ BSDEthernetTap::BSDEthernetTap(
#else #else
/* Other BSDs like OpenBSD only have a limited number of tap devices that cannot be renamed */ /* Other BSDs like OpenBSD only have a limited number of tap devices that cannot be renamed */
for(int i=0;i<64;++i) { for (int i = 0; i < 64; ++i) {
OSUtils::ztsnprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); OSUtils::ztsnprintf(tmpdevname, sizeof(tmpdevname), "tap%d", i);
OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); OSUtils::ztsnprintf(devpath, sizeof(devpath), "/dev/%s", tmpdevname);
_fd = ::open(devpath,O_RDWR); _fd = ::open(devpath, O_RDWR);
if (_fd > 0) { if (_fd > 0) {
_dev = tmpdevname; _dev = tmpdevname;
break; break;
@ -166,25 +171,26 @@ BSDEthernetTap::BSDEthernetTap(
if (_fd <= 0) if (_fd <= 0)
throw std::runtime_error("unable to open TAP device or no more devices available"); throw std::runtime_error("unable to open TAP device or no more devices available");
if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { if (fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL) & ~O_NONBLOCK) == -1) {
::close(_fd); ::close(_fd);
throw std::runtime_error("unable to set flags on file descriptor for TAP device"); throw std::runtime_error("unable to set flags on file descriptor for TAP device");
} }
// Configure MAC address and MTU, bring interface up // Configure MAC address and MTU, bring interface up
OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); OSUtils::ztsnprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]);
OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",_mtu); OSUtils::ztsnprintf(mtustr, sizeof(mtustr), "%u", _mtu);
OSUtils::ztsnprintf(metstr,sizeof(metstr),"%u",_metric); OSUtils::ztsnprintf(metstr, sizeof(metstr), "%u", _metric);
long cpid = (long)vfork(); long cpid = (long)vfork();
if (cpid == 0) { if (cpid == 0) {
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s lladdr %s mtu %s metric %s up" ZT_EOL_S, _dev.c_str(), ethaddr, mtustr, metstr); fprintf(stderr, "DEBUG: ifconfig %s lladdr %s mtu %s metric %s up" ZT_EOL_S, _dev.c_str(), ethaddr, mtustr, metstr);
#endif #endif
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "lladdr", ethaddr, "mtu", mtustr, "metric", metstr, "up", (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
if (exitcode) { if (exitcode) {
::close(_fd); ::close(_fd);
throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
@ -192,7 +198,7 @@ BSDEthernetTap::BSDEthernetTap(
} }
// Set close-on-exec so that devices cannot persist if we fork/exec for update // Set close-on-exec so that devices cannot persist if we fork/exec for update
fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC);
::pipe(_shutdownSignalPipe); ::pipe(_shutdownSignalPipe);
@ -201,23 +207,24 @@ BSDEthernetTap::BSDEthernetTap(
BSDEthernetTap::~BSDEthernetTap() BSDEthernetTap::~BSDEthernetTap()
{ {
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit ::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit
::close(_fd); ::close(_fd);
::close(_shutdownSignalPipe[0]); ::close(_shutdownSignalPipe[0]);
::close(_shutdownSignalPipe[1]); ::close(_shutdownSignalPipe[1]);
long cpid = (long)vfork(); long cpid = (long)vfork();
if (cpid == 0) { if (cpid == 0) {
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s destroy" ZT_EOL_S, _dev.c_str()); fprintf(stderr, "DEBUG: ifconfig %s destroy" ZT_EOL_S, _dev.c_str());
#endif #endif
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "destroy", (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
} }
Thread::join(_thread); Thread::join(_thread);
for (std::thread &t : _rxThreads) { for (std::thread& t : _rxThreads) {
t.join(); t.join();
} }
} }
@ -232,7 +239,7 @@ bool BSDEthernetTap::enabled() const
return _enabled; return _enabled;
} }
static bool ___removeIp(const std::string &_dev,const InetAddress &ip) static bool ___removeIp(const std::string& _dev, const InetAddress& ip)
{ {
long cpid = (long)vfork(); long cpid = (long)vfork();
if (cpid == 0) { if (cpid == 0) {
@ -240,29 +247,30 @@ static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s inet %s -alias" ZT_EOL_S, _dev.c_str(), ip.toIpString(ipbuf)); fprintf(stderr, "DEBUG: ifconfig %s inet %s -alias" ZT_EOL_S, _dev.c_str(), ip.toIpString(ipbuf));
#endif #endif
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString(ipbuf),"-alias",(const char *)0); execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "inet", ip.toIpString(ipbuf), "-alias", (const char*)0);
_exit(-1); _exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
waitpid(cpid,&exitcode,0); waitpid(cpid, &exitcode, 0);
return (exitcode == 0); return (exitcode == 0);
} }
return false; // never reached, make compiler shut up about return value return false; // never reached, make compiler shut up about return value
} }
bool BSDEthernetTap::addIp(const InetAddress &ip) bool BSDEthernetTap::addIp(const InetAddress& ip)
{ {
if (!ip) if (! ip)
return false; return false;
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end())
return true; // IP/netmask already assigned return true; // IP/netmask already assigned
// Remove and reconfigure if address is the same but netmask is different // Remove and reconfigure if address is the same but netmask is different
for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) { for (std::vector<InetAddress>::iterator i(allIps.begin()); i != allIps.end(); ++i) {
if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) { if ((i->ipsEqual(ip)) && (i->netmaskBits() != ip.netmaskBits())) {
if (___removeIp(_dev,*i)) if (___removeIp(_dev, *i))
break; break;
} }
} }
@ -273,23 +281,24 @@ bool BSDEthernetTap::addIp(const InetAddress &ip)
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s %s %s alias" ZT_EOL_S, _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString(tmp)); fprintf(stderr, "DEBUG: ifconfig %s %s %s alias" ZT_EOL_S, _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString(tmp));
#endif #endif
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString(tmp),"alias",(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString(tmp), "alias", (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
return (exitcode == 0); return (exitcode == 0);
} }
return false; return false;
} }
bool BSDEthernetTap::removeIp(const InetAddress &ip) bool BSDEthernetTap::removeIp(const InetAddress& ip)
{ {
if (!ip) if (! ip)
return false; return false;
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) { if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end()) {
if (___removeIp(_dev,ip)) if (___removeIp(_dev, ip))
return true; return true;
} }
return false; return false;
@ -304,28 +313,28 @@ std::vector<InetAddress> BSDEthernetTap::ips() const
} }
_lastIfAddrsUpdate = now; _lastIfAddrsUpdate = now;
struct ifaddrs *ifa = (struct ifaddrs *)0; struct ifaddrs* ifa = (struct ifaddrs*)0;
if (getifaddrs(&ifa)) if (getifaddrs(&ifa))
return std::vector<InetAddress>(); return std::vector<InetAddress>();
std::vector<InetAddress> r; std::vector<InetAddress> r;
struct ifaddrs *p = ifa; struct ifaddrs* p = ifa;
while (p) { while (p) {
if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch(p->ifa_addr->sa_family) { switch (p->ifa_addr->sa_family) {
case AF_INET: { case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr;
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break; } break;
case AF_INET6: { case AF_INET6: {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr;
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask;
uint32_t b[4]; uint32_t b[4];
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); memcpy(b, nm->sin6_addr.s6_addr, sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break; } break;
} }
} }
p = p->ifa_next; p = p->ifa_next;
@ -334,24 +343,24 @@ std::vector<InetAddress> BSDEthernetTap::ips() const
if (ifa) if (ifa)
freeifaddrs(ifa); freeifaddrs(ifa);
std::sort(r.begin(),r.end()); std::sort(r.begin(), r.end());
std::unique(r.begin(),r.end()); std::unique(r.begin(), r.end());
_ifaddrs = r; _ifaddrs = r;
return r; return r;
} }
void BSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) void BSDEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len)
{ {
char putBuf[ZT_MAX_MTU + 64]; char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { if ((_fd > 0) && (len <= _mtu) && (_enabled)) {
to.copyTo(putBuf,6); to.copyTo(putBuf, 6);
from.copyTo(putBuf + 6,6); from.copyTo(putBuf + 6, 6);
*((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); *((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14,data,len); memcpy(putBuf + 14, data, len);
len += 14; len += 14;
::write(_fd,putBuf,len); ::write(_fd, putBuf, len);
} }
} }
@ -360,44 +369,44 @@ std::string BSDEthernetTap::deviceName() const
return _dev; return _dev;
} }
void BSDEthernetTap::setFriendlyName(const char *friendlyName) void BSDEthernetTap::setFriendlyName(const char* friendlyName)
{ {
} }
void BSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed) void BSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed)
{ {
std::vector<MulticastGroup> newGroups; std::vector<MulticastGroup> newGroups;
#ifndef __OpenBSD__ #ifndef __OpenBSD__
struct ifmaddrs *ifmap = (struct ifmaddrs *)0; struct ifmaddrs* ifmap = (struct ifmaddrs*)0;
if (!getifmaddrs(&ifmap)) { if (! getifmaddrs(&ifmap)) {
struct ifmaddrs *p = ifmap; struct ifmaddrs* p = ifmap;
while (p) { while (p) {
if (p->ifma_addr->sa_family == AF_LINK) { if (p->ifma_addr->sa_family == AF_LINK) {
struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name;
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr;
if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0));
} }
p = p->ifma_next; p = p->ifma_next;
} }
freeifmaddrs(ifmap); freeifmaddrs(ifmap);
} }
#endif // __OpenBSD__ #endif // __OpenBSD__
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip) for (std::vector<InetAddress>::iterator ip(allIps.begin()); ip != allIps.end(); ++ip)
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
std::sort(newGroups.begin(),newGroups.end()); std::sort(newGroups.begin(), newGroups.end());
std::unique(newGroups.begin(),newGroups.end()); std::unique(newGroups.begin(), newGroups.end());
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) { for (std::vector<MulticastGroup>::iterator m(newGroups.begin()); m != newGroups.end(); ++m) {
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m))
added.push_back(*m); added.push_back(*m);
} }
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { for (std::vector<MulticastGroup>::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) {
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) if (! std::binary_search(newGroups.begin(), newGroups.end(), *m))
removed.push_back(*m); removed.push_back(*m);
} }
@ -411,21 +420,21 @@ void BSDEthernetTap::setMtu(unsigned int mtu)
long cpid = (long)vfork(); long cpid = (long)vfork();
if (cpid == 0) { if (cpid == 0) {
char tmp[64]; char tmp[64];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu); OSUtils::ztsnprintf(tmp, sizeof(tmp), "%u", mtu);
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s mtu %s" ZT_EOL_S, _dev.c_str(), tmp); fprintf(stderr, "DEBUG: ifconfig %s mtu %s" ZT_EOL_S, _dev.c_str(), tmp);
#endif #endif
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0); execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "mtu", tmp, (const char*)0);
_exit(-1); _exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
waitpid(cpid,&exitcode,0); waitpid(cpid, &exitcode, 0);
} }
} }
} }
void BSDEthernetTap::threadMain() void BSDEthernetTap::threadMain() throw()
throw()
{ {
// Wait for a moment after startup -- wait for Network to finish // Wait for a moment after startup -- wait for Network to finish
// constructing itself. // constructing itself.
@ -436,7 +445,6 @@ void BSDEthernetTap::threadMain()
for (unsigned int i = 0; i < _concurrency; ++i) { for (unsigned int i = 0; i < _concurrency; ++i) {
_rxThreads.push_back(std::thread([this, i, pinning] { _rxThreads.push_back(std::thread([this, i, pinning] {
if (pinning) { if (pinning) {
int pinCore = i % _concurrency; int pinCore = i % _concurrency;
fprintf(stderr, "Pinning thread %d to core %d\n", i, pinCore); fprintf(stderr, "Pinning thread %d to core %d\n", i, pinCore);
@ -444,15 +452,14 @@ void BSDEthernetTap::threadMain()
cpu_set_t cpuset; cpu_set_t cpuset;
CPU_ZERO(&cpuset); CPU_ZERO(&cpuset);
CPU_SET(pinCore, &cpuset); CPU_SET(pinCore, &cpuset);
//int rc = sched_setaffinity(self, sizeof(cpu_set_t), &cpuset); // int rc = sched_setaffinity(self, sizeof(cpu_set_t), &cpuset);
int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset); int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
if (rc != 0) if (rc != 0) {
{
fprintf(stderr, "Failed to pin thread %d to core %d: %s\n", i, pinCore, strerror(errno)); fprintf(stderr, "Failed to pin thread %d to core %d: %s\n", i, pinCore, strerror(errno));
exit(1); exit(1);
} }
} }
#endif // __OpenBSD__ #endif // __OpenBSD__
uint8_t b[ZT_TAP_BUF_SIZE]; uint8_t b[ZT_TAP_BUF_SIZE];
MAC to, from; MAC to, from;
@ -461,37 +468,38 @@ void BSDEthernetTap::threadMain()
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_ZERO(&nullfds); FD_ZERO(&nullfds);
nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1;
r = 0; r = 0;
for(;;) { for (;;) {
FD_SET(_shutdownSignalPipe[0],&readfds); FD_SET(_shutdownSignalPipe[0], &readfds);
FD_SET(_fd,&readfds); FD_SET(_fd, &readfds);
select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0);
if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) // writes to shutdown pipe terminate thread
break; break;
if (FD_ISSET(_fd,&readfds)) { if (FD_ISSET(_fd, &readfds)) {
n = (int)::read(_fd,b + r,sizeof(b) - r); n = (int)::read(_fd, b + r, sizeof(b) - r);
if (n < 0) { if (n < 0) {
if ((errno != EINTR)&&(errno != ETIMEDOUT)) if ((errno != EINTR) && (errno != ETIMEDOUT))
break; break;
} else { }
else {
// Some tap drivers like to send the ethernet frame and the // Some tap drivers like to send the ethernet frame and the
// payload in two chunks, so handle that by accumulating // payload in two chunks, so handle that by accumulating
// data until we have at least a frame. // data until we have at least a frame.
r += n; r += n;
if (r > 14) { if (r > 14) {
if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms
r = _mtu + 14; r = _mtu + 14;
if (_enabled) { if (_enabled) {
to.setTo(b,6); to.setTo(b, 6);
from.setTo(b + 6,6); from.setTo(b + 6, 6);
unsigned int etherType = ntohs(((const uint16_t *)b)[6]); unsigned int etherType = ntohs(((const uint16_t*)b)[6]);
_handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(b + 14),r - 14); _handler(_arg, (void*)0, _nwid, from, to, etherType, 0, (const void*)(b + 14), r - 14);
} }
r = 0; r = 0;
@ -502,7 +510,7 @@ void BSDEthernetTap::threadMain()
#ifndef __OpenBSD__ #ifndef __OpenBSD__
})); }));
} }
#endif // __OpenBSD__ #endif // __OpenBSD__
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,57 +14,56 @@
#ifndef ZT_BSDETHERNETTAP_HPP #ifndef ZT_BSDETHERNETTAP_HPP
#define ZT_BSDETHERNETTAP_HPP #define ZT_BSDETHERNETTAP_HPP
#include "../node/Constants.hpp"
#include "../node/MAC.hpp"
#include "../node/MulticastGroup.hpp"
#include "EthernetTap.hpp"
#include "Thread.hpp"
#include <stdexcept>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include <vector>
#include <stdexcept>
#include <thread> #include <thread>
#include <vector>
#include "../node/Constants.hpp"
#include "../node/MulticastGroup.hpp"
#include "../node/MAC.hpp"
#include "Thread.hpp"
#include "EthernetTap.hpp"
namespace ZeroTier { namespace ZeroTier {
class BSDEthernetTap : public EthernetTap class BSDEthernetTap : public EthernetTap {
{ public:
public:
BSDEthernetTap( BSDEthernetTap(
const char *homePath, const char* homePath,
unsigned int concurrency, unsigned int concurrency,
bool pinning, bool pinning,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg); void* arg);
virtual ~BSDEthernetTap(); virtual ~BSDEthernetTap();
virtual void setEnabled(bool en); virtual void setEnabled(bool en);
virtual bool enabled() const; virtual bool enabled() const;
virtual bool addIp(const InetAddress &ip); virtual bool addIp(const InetAddress& ip);
virtual bool removeIp(const InetAddress &ip); virtual bool removeIp(const InetAddress& ip);
virtual std::vector<InetAddress> ips() const; virtual std::vector<InetAddress> ips() const;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
virtual std::string deviceName() const; virtual std::string deviceName() const;
virtual void setFriendlyName(const char *friendlyName); virtual void setFriendlyName(const char* friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed); virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed);
virtual void setMtu(unsigned int mtu); virtual void setMtu(unsigned int mtu);
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers) {} virtual void setDns(const char* domain, const std::vector<InetAddress>& servers)
{
}
void threadMain() void threadMain() throw();
throw();
private: private:
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int);
void *_arg; void* _arg;
unsigned int _concurrency; unsigned int _concurrency;
bool _pinning; bool _pinning;
uint64_t _nwid; uint64_t _nwid;
@ -81,6 +80,6 @@ private:
std::vector<std::thread> _rxThreads; std::vector<std::thread> _rxThreads;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -22,11 +22,11 @@
#include <string.h> #include <string.h>
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#include <shlobj.h>
#include <winsock2.h>
#include <windows.h>
#include <iphlpapi.h> #include <iphlpapi.h>
#include <netioapi.h> #include <netioapi.h>
#include <shlobj.h>
#include <windows.h>
#include <winsock2.h>
#else #else
#include <ifaddrs.h> #include <ifaddrs.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -34,13 +34,13 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#ifdef __LINUX__ #ifdef __LINUX__
#include <linux/if_addr.h>
#include <net/if.h> #include <net/if.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/if_addr.h>
#endif #endif
#endif #endif
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) #if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK)
#include <net/if.h> #include <net/if.h>
#if TARGET_OS_OSX #if TARGET_OS_OSX
#include <netinet6/in6_var.h> #include <netinet6/in6_var.h>
@ -51,9 +51,9 @@
#include "../node/InetAddress.hpp" #include "../node/InetAddress.hpp"
#include "../node/Mutex.hpp" #include "../node/Mutex.hpp"
#include "../node/Utils.hpp" #include "../node/Utils.hpp"
#include "../osdep/ExtOsdep.hpp"
#include "OSUtils.hpp" #include "OSUtils.hpp"
#include "Phy.hpp" #include "Phy.hpp"
#include "../osdep/ExtOsdep.hpp"
#include <algorithm> #include <algorithm>
#include <atomic> #include <atomic>
@ -132,30 +132,31 @@ class Binder {
template <typename PHY_HANDLER_TYPE, typename INTERFACE_CHECKER> void refresh(Phy<PHY_HANDLER_TYPE>& phy, unsigned int* ports, unsigned int portCount, const std::vector<InetAddress> explicitBind, INTERFACE_CHECKER& ifChecker) template <typename PHY_HANDLER_TYPE, typename INTERFACE_CHECKER> void refresh(Phy<PHY_HANDLER_TYPE>& phy, unsigned int* ports, unsigned int portCount, const std::vector<InetAddress> explicitBind, INTERFACE_CHECKER& ifChecker)
{ {
std::map<InetAddress, std::string> localIfAddrs; std::map<InetAddress, std::string> localIfAddrs;
PhySocket *udps; PhySocket* udps;
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
bool interfacesEnumerated = true; bool interfacesEnumerated = true;
if (explicitBind.empty()) { if (explicitBind.empty()) {
#ifdef ZT_EXTOSDEP #ifdef ZT_EXTOSDEP
std::map<InetAddress,std::string> addrs; std::map<InetAddress, std::string> addrs;
interfacesEnumerated = ExtOsdep::getBindAddrs(addrs); interfacesEnumerated = ExtOsdep::getBindAddrs(addrs);
for (auto &a : addrs) { for (auto& a : addrs) {
auto ip = a.first; auto ip = a.first;
switch(ip.ipScope()) { switch (ip.ipScope()) {
default: break; default:
case InetAddress::IP_SCOPE_PSEUDOPRIVATE: break;
case InetAddress::IP_SCOPE_GLOBAL: case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
case InetAddress::IP_SCOPE_SHARED: case InetAddress::IP_SCOPE_GLOBAL:
case InetAddress::IP_SCOPE_PRIVATE: case InetAddress::IP_SCOPE_SHARED:
for(int x=0;x<(int)portCount;++x) { case InetAddress::IP_SCOPE_PRIVATE:
ip.setPort(ports[x]); for (int x = 0; x < (int)portCount; ++x) {
localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,a.second)); ip.setPort(ports[x]);
} localIfAddrs.insert(std::pair<InetAddress, std::string>(ip, a.second));
break; }
} break;
} }
#else // ZT_EXTOSDEP }
#else // ZT_EXTOSDEP
#ifdef __WINDOWS__ #ifdef __WINDOWS__
char aabuf[32768]; char aabuf[32768];
@ -252,7 +253,7 @@ class Binder {
} }
} }
if ( (flags & IFA_F_TEMPORARY) != 0) { if ((flags & IFA_F_TEMPORARY) != 0) {
continue; continue;
} }
if (devname) { if (devname) {
@ -338,11 +339,11 @@ class Binder {
// //
(void)gotViaProc; (void)gotViaProc;
#if ! defined(__ANDROID__) // getifaddrs() freeifaddrs() not available on Android #if ! defined(__ANDROID__) // getifaddrs() freeifaddrs() not available on Android
if (! gotViaProc) { if (! gotViaProc) {
struct ifaddrs* ifatbl = (struct ifaddrs*)0; struct ifaddrs* ifatbl = (struct ifaddrs*)0;
struct ifaddrs* ifa; struct ifaddrs* ifa;
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) #if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK)
// set up an IPv6 socket so we can check the state of interfaces via SIOCGIFAFLAG_IN6 // set up an IPv6 socket so we can check the state of interfaces via SIOCGIFAFLAG_IN6
int infoSock = socket(AF_INET6, SOCK_DGRAM, 0); int infoSock = socket(AF_INET6, SOCK_DGRAM, 0);
#endif #endif
@ -351,7 +352,7 @@ class Binder {
while (ifa) { while (ifa) {
if ((ifa->ifa_name) && (ifa->ifa_addr)) { if ((ifa->ifa_name) && (ifa->ifa_addr)) {
InetAddress ip = *(ifa->ifa_addr); InetAddress ip = *(ifa->ifa_addr);
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) && TARGET_OS_OSX #if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK) && TARGET_OS_OSX
// Check if the address is an IPv6 Temporary Address, macOS/BSD version // Check if the address is an IPv6 Temporary Address, macOS/BSD version
if (ifa->ifa_addr->sa_family == AF_INET6) { if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ifa->ifa_addr; struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ifa->ifa_addr;
@ -399,7 +400,7 @@ class Binder {
else { else {
interfacesEnumerated = false; interfacesEnumerated = false;
} }
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) #if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK)
close(infoSock); close(infoSock);
#endif #endif
} }
@ -407,7 +408,7 @@ class Binder {
#endif #endif
#endif // ZT_EXTOSDEP #endif // ZT_EXTOSDEP
} }
else { else {
for (std::vector<InetAddress>::const_iterator i(explicitBind.begin()); i != explicitBind.end(); ++i) { for (std::vector<InetAddress>::const_iterator i(explicitBind.begin()); i != explicitBind.end(); ++i) {

View file

@ -14,11 +14,11 @@
#ifndef ZT_BLOCKINGQUEUE_HPP #ifndef ZT_BLOCKINGQUEUE_HPP
#define ZT_BLOCKINGQUEUE_HPP #define ZT_BLOCKINGQUEUE_HPP
#include <queue>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <atomic> #include <atomic>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <vector> #include <vector>
namespace ZeroTier { namespace ZeroTier {
@ -28,11 +28,11 @@ namespace ZeroTier {
* *
* Do not use in node/ since we have not gone C++11 there yet. * Do not use in node/ since we have not gone C++11 there yet.
*/ */
template <class T> template <class T> class BlockingQueue {
class BlockingQueue public:
{ BlockingQueue(void) : r(true)
public: {
BlockingQueue(void) : r(true) {} }
inline void post(T t) inline void post(T t)
{ {
@ -41,16 +41,16 @@ public:
c.notify_one(); c.notify_one();
} }
inline void postLimit(T t,const unsigned long limit) inline void postLimit(T t, const unsigned long limit)
{ {
std::unique_lock<std::mutex> lock(m); std::unique_lock<std::mutex> lock(m);
for(;;) { for (;;) {
if (q.size() < limit) { if (q.size() < limit) {
q.push(t); q.push(t);
c.notify_one(); c.notify_one();
break; break;
} }
if (!r) if (! r)
break; break;
gc.wait(lock); gc.wait(lock);
} }
@ -64,14 +64,14 @@ public:
gc.notify_all(); gc.notify_all();
} }
inline bool get(T &value) inline bool get(T& value)
{ {
std::unique_lock<std::mutex> lock(m); std::unique_lock<std::mutex> lock(m);
if (!r) if (! r)
return false; return false;
while (q.empty()) { while (q.empty()) {
c.wait(lock); c.wait(lock);
if (!r) { if (! r) {
gc.notify_all(); gc.notify_all();
return false; return false;
} }
@ -85,30 +85,25 @@ public:
inline std::vector<T> drain() inline std::vector<T> drain()
{ {
std::vector<T> v; std::vector<T> v;
while (!q.empty()) { while (! q.empty()) {
v.push_back(q.front()); v.push_back(q.front());
q.pop(); q.pop();
} }
return v; return v;
} }
enum TimedWaitResult enum TimedWaitResult { OK, TIMED_OUT, STOP };
{
OK,
TIMED_OUT,
STOP
};
inline TimedWaitResult get(T &value,const unsigned long ms) inline TimedWaitResult get(T& value, const unsigned long ms)
{ {
const std::chrono::milliseconds ms2{ms}; const std::chrono::milliseconds ms2 { ms };
std::unique_lock<std::mutex> lock(m); std::unique_lock<std::mutex> lock(m);
if (!r) if (! r)
return STOP; return STOP;
while (q.empty()) { while (q.empty()) {
if (c.wait_for(lock,ms2) == std::cv_status::timeout) if (c.wait_for(lock, ms2) == std::cv_status::timeout)
return ((r) ? TIMED_OUT : STOP); return ((r) ? TIMED_OUT : STOP);
else if (!r) else if (! r)
return STOP; return STOP;
} }
value = q.front(); value = q.front();
@ -116,17 +111,18 @@ public:
return OK; return OK;
} }
inline size_t size() const { inline size_t size() const
{
return q.size(); return q.size();
} }
private: private:
std::queue<T> q; std::queue<T> q;
mutable std::mutex m; mutable std::mutex m;
mutable std::condition_variable c,gc; mutable std::condition_variable c, gc;
std::atomic_bool r; std::atomic_bool r;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -12,6 +12,7 @@
/****/ /****/
#include "EthernetTap.hpp" #include "EthernetTap.hpp"
#include "OSUtils.hpp" #include "OSUtils.hpp"
#include <stdlib.h> #include <stdlib.h>
@ -20,87 +21,88 @@
#ifdef ZT_SDK #ifdef ZT_SDK
#include "../controller/EmbeddedNetworkController.hpp" #include "../controller/EmbeddedNetworkController.hpp"
#include "../node/Node.hpp"
#include "../include/VirtualTap.hpp" #include "../include/VirtualTap.hpp"
#include "../node/Node.hpp"
#else #else
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/sysctl.h>
#include "MacEthernetTap.hpp" #include "MacEthernetTap.hpp"
#include "MacKextEthernetTap.hpp" #include "MacKextEthernetTap.hpp"
#endif // __APPLE__
#include <sys/sysctl.h>
#endif // __APPLE__
#ifdef __LINUX__ #ifdef __LINUX__
#include "ExtOsdep.hpp" #include "ExtOsdep.hpp"
#include "LinuxEthernetTap.hpp" #include "LinuxEthernetTap.hpp"
#endif // __LINUX__ #endif // __LINUX__
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#include "WindowsEthernetTap.hpp" #include "WindowsEthernetTap.hpp"
#endif // __WINDOWS__ #endif // __WINDOWS__
#ifdef __FreeBSD__ #ifdef __FreeBSD__
#include "BSDEthernetTap.hpp" #include "BSDEthernetTap.hpp"
#endif // __FreeBSD__ #endif // __FreeBSD__
#ifdef __NetBSD__ #ifdef __NetBSD__
#include "NetBSDEthernetTap.hpp" #include "NetBSDEthernetTap.hpp"
#endif // __NetBSD__ #endif // __NetBSD__
#ifdef __OpenBSD__ #ifdef __OpenBSD__
#include "BSDEthernetTap.hpp" #include "BSDEthernetTap.hpp"
#endif // __OpenBSD__ #endif // __OpenBSD__
#endif #endif
namespace ZeroTier { namespace ZeroTier {
std::shared_ptr<EthernetTap> EthernetTap::newInstance( std::shared_ptr<EthernetTap> EthernetTap::newInstance(
const char *tapDeviceType, // OS-specific, NULL for default const char* tapDeviceType, // OS-specific, NULL for default
unsigned int concurrency, unsigned int concurrency,
bool pinning, bool pinning,
const char *homePath, const char* homePath,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg) void* arg)
{ {
#ifdef ZT_SDK #ifdef ZT_SDK
return std::shared_ptr<EthernetTap>(new VirtualTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new VirtualTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
#else // not ZT_SDK #else // not ZT_SDK
#ifdef __APPLE__ #ifdef __APPLE__
char osrelease[256]; char osrelease[256];
size_t size = sizeof(osrelease); size_t size = sizeof(osrelease);
if (sysctlbyname("kern.osrelease",osrelease,&size,nullptr,0) == 0) { if (sysctlbyname("kern.osrelease", osrelease, &size, nullptr, 0) == 0) {
char *dotAt = strchr(osrelease,'.'); char* dotAt = strchr(osrelease, '.');
if (dotAt) { if (dotAt) {
*dotAt = (char)0; *dotAt = (char)0;
// The "feth" virtual Ethernet device type appeared in Darwin 17.x.x. Older versions // The "feth" virtual Ethernet device type appeared in Darwin 17.x.x. Older versions
// (Sierra and earlier) must use the a kernel extension. // (Sierra and earlier) must use the a kernel extension.
if (strtol(osrelease,(char **)0,10) < 17) { if (strtol(osrelease, (char**)0, 10) < 17) {
return std::shared_ptr<EthernetTap>(new MacKextEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new MacKextEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
} else { }
return std::shared_ptr<EthernetTap>(new MacEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); else {
return std::shared_ptr<EthernetTap>(new MacEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
} }
} }
} }
#endif // __APPLE__ #endif // __APPLE__
#ifdef __LINUX__ #ifdef __LINUX__
#ifdef ZT_EXTOSDEP #ifdef ZT_EXTOSDEP
return std::shared_ptr<EthernetTap>(new ExtOsdepTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new ExtOsdepTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
#else #else
return std::shared_ptr<EthernetTap>(new LinuxEthernetTap(homePath,concurrency,pinning,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new LinuxEthernetTap(homePath, concurrency, pinning, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // ZT_EXTOSDEP #endif // ZT_EXTOSDEP
#endif // __LINUX__ #endif // __LINUX__
#ifdef __WINDOWS__ #ifdef __WINDOWS__
HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED);
@ -113,18 +115,8 @@ std::shared_ptr<EthernetTap> EthernetTap::newInstance(
{ {
Mutex::Lock l(_comInit_m); Mutex::Lock l(_comInit_m);
if (!_comInit) { if (! _comInit) {
hres = CoInitializeSecurity( hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL
);
if (FAILED(hres)) { if (FAILED(hres)) {
CoUninitialize(); CoUninitialize();
fprintf(stderr, "WinEthernetTap: Failed to initialize security"); fprintf(stderr, "WinEthernetTap: Failed to initialize security");
@ -133,33 +125,37 @@ std::shared_ptr<EthernetTap> EthernetTap::newInstance(
_comInit = true; _comInit = true;
} }
} }
return std::shared_ptr<EthernetTap>(new WindowsEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new WindowsEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __WINDOWS__ #endif // __WINDOWS__
#ifdef __FreeBSD__ #ifdef __FreeBSD__
return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath,concurrency,pinning,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath, concurrency, pinning, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __FreeBSD__ #endif // __FreeBSD__
#ifdef __NetBSD__ #ifdef __NetBSD__
return std::shared_ptr<EthernetTap>(new NetBSDEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new NetBSDEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __NetBSD__ #endif // __NetBSD__
#ifdef __OpenBSD__ #ifdef __OpenBSD__
return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath,concurrency,pinning,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath, concurrency, pinning, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __OpenBSD__ #endif // __OpenBSD__
#endif // ZT_SDK? #endif // ZT_SDK?
return std::shared_ptr<EthernetTap>(); return std::shared_ptr<EthernetTap>();
} }
EthernetTap::EthernetTap() {} EthernetTap::EthernetTap()
EthernetTap::~EthernetTap() {} {
}
EthernetTap::~EthernetTap()
{
}
bool EthernetTap::addIps(std::vector<InetAddress> ips) bool EthernetTap::addIps(std::vector<InetAddress> ips)
{ {
for(std::vector<InetAddress>::const_iterator i(ips.begin());i!=ips.end();++i) { for (std::vector<InetAddress>::const_iterator i(ips.begin()); i != ips.end(); ++i) {
if (!addIp(*i)) if (! addIp(*i))
return false; return false;
} }
return true; return true;
@ -171,4 +167,4 @@ std::string EthernetTap::friendlyName() const
return std::string(); return std::string();
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -15,52 +15,51 @@
#define ZT_ETHERNETTAP_HPP #define ZT_ETHERNETTAP_HPP
#include "../node/Constants.hpp" #include "../node/Constants.hpp"
#include "../node/MAC.hpp"
#include "../node/InetAddress.hpp" #include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include "../node/MulticastGroup.hpp" #include "../node/MulticastGroup.hpp"
#include <string>
#include <memory> #include <memory>
#include <string>
#include <vector> #include <vector>
#define GETIFADDRS_CACHE_TIME 1000 #define GETIFADDRS_CACHE_TIME 1000
namespace ZeroTier { namespace ZeroTier {
class EthernetTap class EthernetTap {
{ public:
public:
static std::shared_ptr<EthernetTap> newInstance( static std::shared_ptr<EthernetTap> newInstance(
const char *tapDeviceType, // OS-specific, NULL for default const char* tapDeviceType, // OS-specific, NULL for default
unsigned int concurrency, unsigned int concurrency,
bool pinning, bool pinning,
const char *homePath, const char* homePath,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg); void* arg);
EthernetTap(); EthernetTap();
virtual ~EthernetTap(); virtual ~EthernetTap();
virtual void setEnabled(bool en) = 0; virtual void setEnabled(bool en) = 0;
virtual bool enabled() const = 0; virtual bool enabled() const = 0;
virtual bool addIp(const InetAddress &ip) = 0; virtual bool addIp(const InetAddress& ip) = 0;
virtual bool addIps(std::vector<InetAddress> ips); // uses addIp() unless overridden virtual bool addIps(std::vector<InetAddress> ips); // uses addIp() unless overridden
virtual bool removeIp(const InetAddress &ip) = 0; virtual bool removeIp(const InetAddress& ip) = 0;
virtual std::vector<InetAddress> ips() const = 0; virtual std::vector<InetAddress> ips() const = 0;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) = 0; virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len) = 0;
virtual std::string deviceName() const = 0; virtual std::string deviceName() const = 0;
virtual void setFriendlyName(const char *friendlyName) = 0; virtual void setFriendlyName(const char* friendlyName) = 0;
virtual std::string friendlyName() const; virtual std::string friendlyName() const;
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed) = 0; virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed) = 0;
virtual void setMtu(unsigned int mtu) = 0; virtual void setMtu(unsigned int mtu) = 0;
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers) = 0; virtual void setDns(const char* domain, const std::vector<InetAddress>& servers) = 0;
}; };
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -11,15 +11,16 @@
*/ */
/****/ /****/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "Http.hpp" #include "Http.hpp"
#include "Phy.hpp"
#include "OSUtils.hpp"
#include "../node/Constants.hpp" #include "../node/Constants.hpp"
#include "../node/Utils.hpp" #include "../node/Utils.hpp"
#include "OSUtils.hpp"
#include "Phy.hpp"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifdef ZT_USE_SYSTEM_HTTP_PARSER #ifdef ZT_USE_SYSTEM_HTTP_PARSER
#include <http_parser.h> #include <http_parser.h>
@ -31,90 +32,87 @@ namespace ZeroTier {
namespace { namespace {
static int ShttpOnMessageBegin(http_parser *parser); static int ShttpOnMessageBegin(http_parser* parser);
static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length); static int ShttpOnUrl(http_parser* parser, const char* ptr, size_t length);
#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)
static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length); static int ShttpOnStatus(http_parser* parser, const char* ptr, size_t length);
#else #else
static int ShttpOnStatus(http_parser *parser); static int ShttpOnStatus(http_parser* parser);
#endif #endif
static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length); static int ShttpOnHeaderField(http_parser* parser, const char* ptr, size_t length);
static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length); static int ShttpOnValue(http_parser* parser, const char* ptr, size_t length);
static int ShttpOnHeadersComplete(http_parser *parser); static int ShttpOnHeadersComplete(http_parser* parser);
static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length); static int ShttpOnBody(http_parser* parser, const char* ptr, size_t length);
static int ShttpOnMessageComplete(http_parser *parser); static int ShttpOnMessageComplete(http_parser* parser);
#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 1) #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 1)
static const struct http_parser_settings HTTP_PARSER_SETTINGS = { static const struct http_parser_settings HTTP_PARSER_SETTINGS = { ShttpOnMessageBegin, ShttpOnUrl, ShttpOnStatus, ShttpOnHeaderField, ShttpOnValue, ShttpOnHeadersComplete, ShttpOnBody, ShttpOnMessageComplete };
ShttpOnMessageBegin,
ShttpOnUrl,
ShttpOnStatus,
ShttpOnHeaderField,
ShttpOnValue,
ShttpOnHeadersComplete,
ShttpOnBody,
ShttpOnMessageComplete
};
#else #else
static const struct http_parser_settings HTTP_PARSER_SETTINGS = { static const struct http_parser_settings HTTP_PARSER_SETTINGS = { ShttpOnMessageBegin, ShttpOnUrl, ShttpOnHeaderField, ShttpOnValue, ShttpOnHeadersComplete, ShttpOnBody, ShttpOnMessageComplete };
ShttpOnMessageBegin,
ShttpOnUrl,
ShttpOnHeaderField,
ShttpOnValue,
ShttpOnHeadersComplete,
ShttpOnBody,
ShttpOnMessageComplete
};
#endif #endif
struct HttpPhyHandler struct HttpPhyHandler {
{
// not used // not used
inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) {} inline void phyOnDatagram(PhySocket* sock, void** uptr, const struct sockaddr* localAddr, const struct sockaddr* from, void* data, unsigned long len)
inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) {} {
}
inline void phyOnTcpAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN, const struct sockaddr* from)
{
}
inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) inline void phyOnTcpConnect(PhySocket* sock, void** uptr, bool success)
{ {
if (success) { if (success) {
phy->setNotifyWritable(sock,true); phy->setNotifyWritable(sock, true);
} else { }
else {
*responseBody = "connection failed"; *responseBody = "connection failed";
error = true; error = true;
done = true; done = true;
} }
} }
inline void phyOnTcpClose(PhySocket *sock,void **uptr) inline void phyOnTcpClose(PhySocket* sock, void** uptr)
{ {
done = true; done = true;
} }
inline void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) inline void phyOnTcpData(PhySocket* sock, void** uptr, void* data, unsigned long len)
{ {
lastActivity = OSUtils::now(); lastActivity = OSUtils::now();
http_parser_execute(&parser,&HTTP_PARSER_SETTINGS,(const char *)data,len); http_parser_execute(&parser, &HTTP_PARSER_SETTINGS, (const char*)data, len);
if ((parser.upgrade)||(parser.http_errno != HPE_OK)) if ((parser.upgrade) || (parser.http_errno != HPE_OK))
phy->close(sock); phy->close(sock);
} }
inline void phyOnTcpWritable(PhySocket *sock,void **uptr) inline void phyOnTcpWritable(PhySocket* sock, void** uptr)
{ {
if (writePtr < (unsigned long)writeBuf.length()) { if (writePtr < (unsigned long)writeBuf.length()) {
long n = phy->streamSend(sock,writeBuf.data() + writePtr,(unsigned long)writeBuf.length() - writePtr,true); long n = phy->streamSend(sock, writeBuf.data() + writePtr, (unsigned long)writeBuf.length() - writePtr, true);
if (n > 0) if (n > 0)
writePtr += n; writePtr += n;
} }
if (writePtr >= (unsigned long)writeBuf.length()) if (writePtr >= (unsigned long)writeBuf.length())
phy->setNotifyWritable(sock,false); phy->setNotifyWritable(sock, false);
} }
inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {} inline void phyOnFileDescriptorActivity(PhySocket* sock, void** uptr, bool readable, bool writable)
{
}
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {} inline void phyOnUnixAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN)
inline void phyOnUnixClose(PhySocket *sock,void **uptr) {} {
inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} }
inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {} inline void phyOnUnixClose(PhySocket* sock, void** uptr)
#endif // __UNIX_LIKE__ {
}
inline void phyOnUnixData(PhySocket* sock, void** uptr, void* data, unsigned long len)
{
}
inline void phyOnUnixWritable(PhySocket* sock, void** uptr)
{
}
#endif // __UNIX_LIKE__
http_parser parser; http_parser parser;
std::string currentHeaderField; std::string currentHeaderField;
@ -125,27 +123,27 @@ struct HttpPhyHandler
std::string writeBuf; std::string writeBuf;
unsigned long maxResponseSize; unsigned long maxResponseSize;
std::map<std::string,std::string> *responseHeaders; std::map<std::string, std::string>* responseHeaders;
std::string *responseBody; std::string* responseBody;
bool error; bool error;
bool done; bool done;
Phy<HttpPhyHandler *> *phy; Phy<HttpPhyHandler*>* phy;
PhySocket *sock; PhySocket* sock;
}; };
static int ShttpOnMessageBegin(http_parser *parser) static int ShttpOnMessageBegin(http_parser* parser)
{ {
return 0; return 0;
} }
static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) static int ShttpOnUrl(http_parser* parser, const char* ptr, size_t length)
{ {
return 0; return 0;
} }
#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)
static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) static int ShttpOnStatus(http_parser* parser, const char* ptr, size_t length)
#else #else
static int ShttpOnStatus(http_parser *parser) static int ShttpOnStatus(http_parser* parser)
#endif #endif
{ {
/* /*
@ -156,66 +154,66 @@ static int ShttpOnStatus(http_parser *parser)
*/ */
return 0; return 0;
} }
static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) static int ShttpOnHeaderField(http_parser* parser, const char* ptr, size_t length)
{ {
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data); HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->messageSize += (unsigned long)length; hh->messageSize += (unsigned long)length;
if (hh->messageSize > hh->maxResponseSize) if (hh->messageSize > hh->maxResponseSize)
return -1; return -1;
if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) { if ((hh->currentHeaderField.length()) && (hh->currentHeaderValue.length())) {
(*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue;
hh->currentHeaderField = ""; hh->currentHeaderField = "";
hh->currentHeaderValue = ""; hh->currentHeaderValue = "";
} }
for(size_t i=0;i<length;++i) for (size_t i = 0; i < length; ++i)
hh->currentHeaderField.push_back(OSUtils::toLower(ptr[i])); hh->currentHeaderField.push_back(OSUtils::toLower(ptr[i]));
return 0; return 0;
} }
static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) static int ShttpOnValue(http_parser* parser, const char* ptr, size_t length)
{ {
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data); HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->messageSize += (unsigned long)length; hh->messageSize += (unsigned long)length;
if (hh->messageSize > hh->maxResponseSize) if (hh->messageSize > hh->maxResponseSize)
return -1; return -1;
hh->currentHeaderValue.append(ptr,length); hh->currentHeaderValue.append(ptr, length);
return 0; return 0;
} }
static int ShttpOnHeadersComplete(http_parser *parser) static int ShttpOnHeadersComplete(http_parser* parser)
{ {
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data); HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) if ((hh->currentHeaderField.length()) && (hh->currentHeaderValue.length()))
(*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue;
return 0; return 0;
} }
static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) static int ShttpOnBody(http_parser* parser, const char* ptr, size_t length)
{ {
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data); HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->messageSize += (unsigned long)length; hh->messageSize += (unsigned long)length;
if (hh->messageSize > hh->maxResponseSize) if (hh->messageSize > hh->maxResponseSize)
return -1; return -1;
hh->responseBody->append(ptr,length); hh->responseBody->append(ptr, length);
return 0; return 0;
} }
static int ShttpOnMessageComplete(http_parser *parser) static int ShttpOnMessageComplete(http_parser* parser)
{ {
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data); HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->phy->close(hh->sock); hh->phy->close(hh->sock);
return 0; return 0;
} }
} // anonymous namespace } // anonymous namespace
unsigned int Http::_do( unsigned int Http::_do(
const char *method, const char* method,
unsigned long maxResponseSize, unsigned long maxResponseSize,
unsigned long timeout, unsigned long timeout,
const struct sockaddr *remoteAddress, const struct sockaddr* remoteAddress,
const char *path, const char* path,
const std::map<std::string,std::string> &requestHeaders, const std::map<std::string, std::string>& requestHeaders,
const void *requestBody, const void* requestBody,
unsigned long requestBodyLength, unsigned long requestBodyLength,
std::map<std::string,std::string> &responseHeaders, std::map<std::string, std::string>& responseHeaders,
std::string &responseBody) std::string& responseBody)
{ {
try { try {
responseHeaders.clear(); responseHeaders.clear();
@ -223,31 +221,33 @@ unsigned int Http::_do(
HttpPhyHandler handler; HttpPhyHandler handler;
http_parser_init(&(handler.parser),HTTP_RESPONSE); http_parser_init(&(handler.parser), HTTP_RESPONSE);
handler.parser.data = (void *)&handler; handler.parser.data = (void*)&handler;
handler.messageSize = 0; handler.messageSize = 0;
handler.writePtr = 0; handler.writePtr = 0;
handler.lastActivity = OSUtils::now(); handler.lastActivity = OSUtils::now();
try { try {
char tmp[1024]; char tmp[1024];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s %s HTTP/1.1\r\n",method,path); OSUtils::ztsnprintf(tmp, sizeof(tmp), "%s %s HTTP/1.1\r\n", method, path);
handler.writeBuf.append(tmp); handler.writeBuf.append(tmp);
for(std::map<std::string,std::string>::const_iterator h(requestHeaders.begin());h!=requestHeaders.end();++h) { for (std::map<std::string, std::string>::const_iterator h(requestHeaders.begin()); h != requestHeaders.end(); ++h) {
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s: %s\r\n",h->first.c_str(),h->second.c_str()); OSUtils::ztsnprintf(tmp, sizeof(tmp), "%s: %s\r\n", h->first.c_str(), h->second.c_str());
handler.writeBuf.append(tmp); handler.writeBuf.append(tmp);
} }
handler.writeBuf.append("\r\n"); handler.writeBuf.append("\r\n");
if ((requestBody)&&(requestBodyLength)) if ((requestBody) && (requestBodyLength))
handler.writeBuf.append((const char *)requestBody,requestBodyLength); handler.writeBuf.append((const char*)requestBody, requestBodyLength);
} catch ( ... ) { }
catch (...) {
responseBody = "request too large"; responseBody = "request too large";
return 0; return 0;
} }
if (maxResponseSize) { if (maxResponseSize) {
handler.maxResponseSize = maxResponseSize; handler.maxResponseSize = maxResponseSize;
} else { }
else {
handler.maxResponseSize = 2147483647; handler.maxResponseSize = 2147483647;
} }
handler.responseHeaders = &responseHeaders; handler.responseHeaders = &responseHeaders;
@ -255,19 +255,19 @@ unsigned int Http::_do(
handler.error = false; handler.error = false;
handler.done = false; handler.done = false;
Phy<HttpPhyHandler *> phy(&handler,true,true); Phy<HttpPhyHandler*> phy(&handler, true, true);
bool instantConnect = false; bool instantConnect = false;
handler.phy = &phy; handler.phy = &phy;
handler.sock = phy.tcpConnect((const struct sockaddr *)remoteAddress,instantConnect,(void *)0,true); handler.sock = phy.tcpConnect((const struct sockaddr*)remoteAddress, instantConnect, (void*)0, true);
if (!handler.sock) { if (! handler.sock) {
responseBody = "connection failed (2)"; responseBody = "connection failed (2)";
return 0; return 0;
} }
while (!handler.done) { while (! handler.done) {
phy.poll(timeout / 2); phy.poll(timeout / 2);
if ((timeout)&&((unsigned long)(OSUtils::now() - handler.lastActivity) > timeout)) { if ((timeout) && ((unsigned long)(OSUtils::now() - handler.lastActivity) > timeout)) {
phy.close(handler.sock); phy.close(handler.sock);
responseBody = "timed out"; responseBody = "timed out";
return 0; return 0;
@ -275,13 +275,15 @@ unsigned int Http::_do(
} }
return ((handler.error) ? 0 : ((handler.parser.http_errno != HPE_OK) ? 0 : handler.parser.status_code)); return ((handler.error) ? 0 : ((handler.parser.http_errno != HPE_OK) ? 0 : handler.parser.status_code));
} catch (std::exception &exc) { }
catch (std::exception& exc) {
responseBody = exc.what(); responseBody = exc.what();
return 0; return 0;
} catch ( ... ) { }
catch (...) {
responseBody = "unknown exception"; responseBody = "unknown exception";
return 0; return 0;
} }
} }
} // namespace ZeroTier } // namespace ZeroTier

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