added ZTO files
This commit is contained in:
1842
zerotierone/controller/EmbeddedNetworkController.cpp
Normal file
1842
zerotierone/controller/EmbeddedNetworkController.cpp
Normal file
File diff suppressed because it is too large
Load Diff
217
zerotierone/controller/EmbeddedNetworkController.hpp
Normal file
217
zerotierone/controller/EmbeddedNetworkController.hpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_SQLITENETWORKCONTROLLER_HPP
|
||||
#define ZT_SQLITENETWORKCONTROLLER_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <list>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
|
||||
#include "../node/NetworkController.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/Address.hpp"
|
||||
#include "../node/InetAddress.hpp"
|
||||
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
#include "../osdep/Thread.hpp"
|
||||
#include "../osdep/BlockingQueue.hpp"
|
||||
|
||||
#include "../ext/json/json.hpp"
|
||||
|
||||
#include "JSONDB.hpp"
|
||||
|
||||
// Number of background threads to start -- not actually started until needed
|
||||
#define ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT 2
|
||||
|
||||
// TTL for circuit tests
|
||||
#define ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION 120000
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class Node;
|
||||
|
||||
class EmbeddedNetworkController : public NetworkController
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param node Parent node
|
||||
* @param dbPath Path to store data
|
||||
*/
|
||||
EmbeddedNetworkController(Node *node,const char *dbPath);
|
||||
virtual ~EmbeddedNetworkController();
|
||||
|
||||
virtual void init(const Identity &signingId,Sender *sender);
|
||||
|
||||
virtual void request(
|
||||
uint64_t nwid,
|
||||
const InetAddress &fromAddr,
|
||||
uint64_t requestPacketId,
|
||||
const Identity &identity,
|
||||
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
|
||||
|
||||
unsigned int handleControlPlaneHttpGET(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
unsigned int handleControlPlaneHttpPOST(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
unsigned int handleControlPlaneHttpDELETE(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
|
||||
void threadMain()
|
||||
throw();
|
||||
|
||||
private:
|
||||
static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report);
|
||||
void _request(
|
||||
uint64_t nwid,
|
||||
const InetAddress &fromAddr,
|
||||
uint64_t requestPacketId,
|
||||
const Identity &identity,
|
||||
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
|
||||
|
||||
struct _RQEntry
|
||||
{
|
||||
uint64_t nwid;
|
||||
uint64_t requestPacketId;
|
||||
InetAddress fromAddr;
|
||||
Identity identity;
|
||||
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> metaData;
|
||||
};
|
||||
BlockingQueue<_RQEntry *> _queue;
|
||||
|
||||
Thread _threads[ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT];
|
||||
bool _threadsStarted;
|
||||
Mutex _threads_m;
|
||||
|
||||
// Gathers a bunch of statistics about members of a network, IP assignments, etc. that we need in various places
|
||||
struct _NetworkMemberInfo
|
||||
{
|
||||
_NetworkMemberInfo() : authorizedMemberCount(0),activeMemberCount(0),totalMemberCount(0),mostRecentDeauthTime(0) {}
|
||||
std::set<Address> activeBridges;
|
||||
std::set<InetAddress> allocatedIps;
|
||||
unsigned long authorizedMemberCount;
|
||||
unsigned long activeMemberCount;
|
||||
unsigned long totalMemberCount;
|
||||
uint64_t mostRecentDeauthTime;
|
||||
uint64_t nmiTimestamp; // time this NMI structure was computed
|
||||
};
|
||||
std::map<uint64_t,_NetworkMemberInfo> _nmiCache;
|
||||
Mutex _nmiCache_m;
|
||||
void _getNetworkMemberInfo(uint64_t now,uint64_t nwid,_NetworkMemberInfo &nmi);
|
||||
inline void _clearNetworkMemberInfoCache(const uint64_t nwid)
|
||||
{
|
||||
Mutex::Lock _l(_nmiCache_m);
|
||||
_nmiCache.erase(nwid);
|
||||
}
|
||||
|
||||
void _pushMemberUpdate(uint64_t now,uint64_t nwid,const nlohmann::json &member);
|
||||
|
||||
// These init objects with default and static/informational fields
|
||||
inline void _initMember(nlohmann::json &member)
|
||||
{
|
||||
if (!member.count("authorized")) member["authorized"] = false;
|
||||
if (!member.count("authHistory")) member["authHistory"] = nlohmann::json::array();
|
||||
if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array();
|
||||
if (!member.count("recentLog")) member["recentLog"] = nlohmann::json::array();
|
||||
if (!member.count("activeBridge")) member["activeBridge"] = false;
|
||||
if (!member.count("tags")) member["tags"] = nlohmann::json::array();
|
||||
if (!member.count("capabilities")) member["capabilities"] = nlohmann::json::array();
|
||||
if (!member.count("creationTime")) member["creationTime"] = OSUtils::now();
|
||||
if (!member.count("noAutoAssignIps")) member["noAutoAssignIps"] = false;
|
||||
if (!member.count("revision")) member["revision"] = 0ULL;
|
||||
if (!member.count("lastDeauthorizedTime")) member["lastDeauthorizedTime"] = 0ULL;
|
||||
if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL;
|
||||
member["objtype"] = "member";
|
||||
}
|
||||
inline void _initNetwork(nlohmann::json &network)
|
||||
{
|
||||
if (!network.count("private")) network["private"] = true;
|
||||
if (!network.count("creationTime")) network["creationTime"] = OSUtils::now();
|
||||
if (!network.count("name")) network["name"] = "";
|
||||
if (!network.count("multicastLimit")) network["multicastLimit"] = (uint64_t)32;
|
||||
if (!network.count("enableBroadcast")) network["enableBroadcast"] = true;
|
||||
if (!network.count("v4AssignMode")) network["v4AssignMode"] = {{"zt",false}};
|
||||
if (!network.count("v6AssignMode")) network["v6AssignMode"] = {{"rfc4193",false},{"zt",false},{"6plane",false}};
|
||||
if (!network.count("authTokens")) network["authTokens"] = nlohmann::json::array();
|
||||
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("rules")) {
|
||||
// If unspecified, rules are set to allow anything and behave like a flat L2 segment
|
||||
network["rules"] = {{
|
||||
{ "not",false },
|
||||
{ "or", false },
|
||||
{ "type","ACTION_ACCEPT" }
|
||||
}};
|
||||
}
|
||||
network["objtype"] = "network";
|
||||
}
|
||||
inline void _addNetworkNonPersistedFields(nlohmann::json &network,uint64_t now,const _NetworkMemberInfo &nmi)
|
||||
{
|
||||
network["clock"] = now;
|
||||
network["authorizedMemberCount"] = nmi.authorizedMemberCount;
|
||||
network["activeMemberCount"] = nmi.activeMemberCount;
|
||||
network["totalMemberCount"] = nmi.totalMemberCount;
|
||||
}
|
||||
inline void _addMemberNonPersistedFields(nlohmann::json &member,uint64_t now)
|
||||
{
|
||||
member["clock"] = now;
|
||||
}
|
||||
|
||||
JSONDB _db;
|
||||
Mutex _db_m;
|
||||
|
||||
Node *const _node;
|
||||
std::string _path;
|
||||
|
||||
NetworkController::Sender *_sender;
|
||||
Identity _signingId;
|
||||
|
||||
std::list< ZT_CircuitTest > _tests;
|
||||
Mutex _tests_m;
|
||||
|
||||
std::map< std::pair<uint64_t,uint64_t>,uint64_t > _lastRequestTime; // last request time by <address,networkId>
|
||||
Mutex _lastRequestTime_m;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
184
zerotierone/controller/JSONDB.cpp
Normal file
184
zerotierone/controller/JSONDB.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "JSONDB.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
static const nlohmann::json _EMPTY_JSON(nlohmann::json::object());
|
||||
|
||||
bool JSONDB::writeRaw(const std::string &n,const std::string &obj)
|
||||
{
|
||||
if (!_isValidObjectName(n))
|
||||
return false;
|
||||
|
||||
const std::string path(_genPath(n,true));
|
||||
if (!path.length())
|
||||
return false;
|
||||
|
||||
const std::string buf(obj);
|
||||
if (!OSUtils::writeFile(path.c_str(),buf))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSONDB::put(const std::string &n,const nlohmann::json &obj)
|
||||
{
|
||||
if (!_isValidObjectName(n))
|
||||
return false;
|
||||
|
||||
const std::string path(_genPath(n,true));
|
||||
if (!path.length())
|
||||
return false;
|
||||
|
||||
const std::string buf(OSUtils::jsonDump(obj));
|
||||
if (!OSUtils::writeFile(path.c_str(),buf))
|
||||
return false;
|
||||
|
||||
_E &e = _db[n];
|
||||
e.obj = obj;
|
||||
e.lastModifiedOnDisk = OSUtils::getLastModified(path.c_str());
|
||||
e.lastCheck = OSUtils::now();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const nlohmann::json &JSONDB::get(const std::string &n,unsigned long maxSinceCheck)
|
||||
{
|
||||
if (!_isValidObjectName(n))
|
||||
return _EMPTY_JSON;
|
||||
|
||||
const uint64_t now = OSUtils::now();
|
||||
std::string buf;
|
||||
std::map<std::string,_E>::iterator e(_db.find(n));
|
||||
|
||||
if (e != _db.end()) {
|
||||
if ((now - e->second.lastCheck) <= (uint64_t)maxSinceCheck)
|
||||
return e->second.obj;
|
||||
|
||||
const std::string path(_genPath(n,false));
|
||||
if (!path.length()) // sanity check
|
||||
return _EMPTY_JSON;
|
||||
|
||||
// We are somewhat tolerant to momentary disk failures here. This may
|
||||
// occur over e.g. EC2's elastic filesystem (NFS).
|
||||
const uint64_t lm = OSUtils::getLastModified(path.c_str());
|
||||
if (e->second.lastModifiedOnDisk != lm) {
|
||||
if (OSUtils::readFile(path.c_str(),buf)) {
|
||||
try {
|
||||
e->second.obj = OSUtils::jsonParse(buf);
|
||||
e->second.lastModifiedOnDisk = lm; // don't update these if there is a parse error -- try again and again ASAP
|
||||
e->second.lastCheck = now;
|
||||
} catch ( ... ) {} // parse errors result in "holding pattern" behavior
|
||||
}
|
||||
}
|
||||
|
||||
return e->second.obj;
|
||||
} else {
|
||||
const std::string path(_genPath(n,false));
|
||||
if (!path.length())
|
||||
return _EMPTY_JSON;
|
||||
|
||||
if (!OSUtils::readFile(path.c_str(),buf))
|
||||
return _EMPTY_JSON;
|
||||
|
||||
const uint64_t lm = OSUtils::getLastModified(path.c_str());
|
||||
_E &e2 = _db[n];
|
||||
try {
|
||||
e2.obj = OSUtils::jsonParse(buf);
|
||||
} catch ( ... ) {
|
||||
e2.obj = _EMPTY_JSON;
|
||||
buf = "{}";
|
||||
}
|
||||
e2.lastModifiedOnDisk = lm;
|
||||
e2.lastCheck = now;
|
||||
|
||||
return e2.obj;
|
||||
}
|
||||
}
|
||||
|
||||
void JSONDB::erase(const std::string &n)
|
||||
{
|
||||
if (!_isValidObjectName(n))
|
||||
return;
|
||||
|
||||
std::string path(_genPath(n,true));
|
||||
if (!path.length())
|
||||
return;
|
||||
|
||||
OSUtils::rm(path.c_str());
|
||||
_db.erase(n);
|
||||
}
|
||||
|
||||
void JSONDB::_reload(const std::string &p)
|
||||
{
|
||||
std::map<std::string,char> l(OSUtils::listDirectoryFull(p.c_str()));
|
||||
for(std::map<std::string,char>::iterator li(l.begin());li!=l.end();++li) {
|
||||
if (li->second == 'f') {
|
||||
// assume p starts with _basePath, which it always does -- will throw otherwise
|
||||
std::string n(p.substr(_basePath.length()));
|
||||
while ((n.length() > 0)&&(n[0] == ZT_PATH_SEPARATOR)) n = n.substr(1);
|
||||
if (ZT_PATH_SEPARATOR != '/') std::replace(n.begin(),n.end(),ZT_PATH_SEPARATOR,'/');
|
||||
if ((n.length() > 0)&&(n[n.length() - 1] != '/')) n.push_back('/');
|
||||
n.append(li->first);
|
||||
if ((n.length() > 5)&&(n.substr(n.length() - 5) == ".json")) {
|
||||
this->get(n.substr(0,n.length() - 5),0); // causes load and cache or update
|
||||
}
|
||||
} else if (li->second == 'd') {
|
||||
this->_reload(p + ZT_PATH_SEPARATOR + li->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool JSONDB::_isValidObjectName(const std::string &n)
|
||||
{
|
||||
if (n.length() == 0)
|
||||
return false;
|
||||
const char *p = n.c_str();
|
||||
char c;
|
||||
// For security reasons we should not allow dots, backslashes, or other path characters or potential path characters.
|
||||
while ((c = *(p++))) {
|
||||
if (!( ((c >= 'a')&&(c <= 'z')) || ((c >= 'A')&&(c <= 'Z')) || ((c >= '0')&&(c <= '9')) || (c == '/') || (c == '_') || (c == '~') || (c == '-') ))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string JSONDB::_genPath(const std::string &n,bool create)
|
||||
{
|
||||
std::vector<std::string> pt(OSUtils::split(n.c_str(),"/","",""));
|
||||
if (pt.size() == 0)
|
||||
return std::string();
|
||||
|
||||
std::string p(_basePath);
|
||||
if (create) OSUtils::mkdir(p.c_str());
|
||||
for(unsigned long i=0,j=(unsigned long)(pt.size()-1);i<j;++i) {
|
||||
p.push_back(ZT_PATH_SEPARATOR);
|
||||
p.append(pt[i]);
|
||||
if (create) OSUtils::mkdir(p.c_str());
|
||||
}
|
||||
|
||||
p.push_back(ZT_PATH_SEPARATOR);
|
||||
p.append(pt[pt.size()-1]);
|
||||
p.append(".json");
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
118
zerotierone/controller/JSONDB.hpp
Normal file
118
zerotierone/controller/JSONDB.hpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_JSONDB_HPP
|
||||
#define ZT_JSONDB_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../ext/json/json.hpp"
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Hierarchical JSON store that persists into the filesystem
|
||||
*/
|
||||
class JSONDB
|
||||
{
|
||||
public:
|
||||
JSONDB(const std::string &basePath) :
|
||||
_basePath(basePath)
|
||||
{
|
||||
_reload(_basePath);
|
||||
}
|
||||
|
||||
inline void reload()
|
||||
{
|
||||
_db.clear();
|
||||
_reload(_basePath);
|
||||
}
|
||||
|
||||
bool writeRaw(const std::string &n,const std::string &obj);
|
||||
|
||||
bool put(const std::string &n,const nlohmann::json &obj);
|
||||
|
||||
inline bool put(const std::string &n1,const std::string &n2,const nlohmann::json &obj) { return this->put((n1 + "/" + n2),obj); }
|
||||
inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3),obj); }
|
||||
inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3 + "/" + n4),obj); }
|
||||
inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5),obj); }
|
||||
|
||||
const nlohmann::json &get(const std::string &n,unsigned long maxSinceCheck = 0);
|
||||
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2,unsigned long maxSinceCheck = 0) { return this->get((n1 + "/" + n2),maxSinceCheck); }
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3,unsigned long maxSinceCheck = 0) { return this->get((n1 + "/" + n2 + "/" + n3),maxSinceCheck); }
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,unsigned long maxSinceCheck = 0) { return this->get((n1 + "/" + n2 + "/" + n3 + "/" + n4),maxSinceCheck); }
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5,unsigned long maxSinceCheck = 0) { return this->get((n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5),maxSinceCheck); }
|
||||
|
||||
void erase(const std::string &n);
|
||||
|
||||
inline void erase(const std::string &n1,const std::string &n2) { this->erase(n1 + "/" + n2); }
|
||||
inline void erase(const std::string &n1,const std::string &n2,const std::string &n3) { this->erase(n1 + "/" + n2 + "/" + n3); }
|
||||
inline void erase(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4) { this->erase(n1 + "/" + n2 + "/" + n3 + "/" + n4); }
|
||||
inline void erase(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5) { this->erase(n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5); }
|
||||
|
||||
template<typename F>
|
||||
inline void filter(const std::string &prefix,unsigned long maxSinceCheck,F func)
|
||||
{
|
||||
for(std::map<std::string,_E>::iterator i(_db.lower_bound(prefix));i!=_db.end();) {
|
||||
if ((i->first.length() >= prefix.length())&&(!memcmp(i->first.data(),prefix.data(),prefix.length()))) {
|
||||
if (!func(i->first,get(i->first,maxSinceCheck))) {
|
||||
std::map<std::string,_E>::iterator i2(i); ++i2;
|
||||
this->erase(i->first);
|
||||
i = i2;
|
||||
} else ++i;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool operator==(const JSONDB &db) const { return ((_basePath == db._basePath)&&(_db == db._db)); }
|
||||
inline bool operator!=(const JSONDB &db) const { return (!(*this == db)); }
|
||||
|
||||
private:
|
||||
void _reload(const std::string &p);
|
||||
bool _isValidObjectName(const std::string &n);
|
||||
std::string _genPath(const std::string &n,bool create);
|
||||
|
||||
struct _E
|
||||
{
|
||||
nlohmann::json obj;
|
||||
uint64_t lastModifiedOnDisk;
|
||||
uint64_t lastCheck;
|
||||
|
||||
inline bool operator==(const _E &e) const { return (obj == e.obj); }
|
||||
inline bool operator!=(const _E &e) const { return (obj != e.obj); }
|
||||
};
|
||||
|
||||
std::string _basePath;
|
||||
std::map<std::string,_E> _db;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
248
zerotierone/controller/README.md
Normal file
248
zerotierone/controller/README.md
Normal file
@@ -0,0 +1,248 @@
|
||||
Network Controller Microservice
|
||||
======
|
||||
|
||||
Every ZeroTier virtual network has a *network controller*. This is our reference implementation and is the same one we use to power our own hosted services at [my.zerotier.com](https://my.zerotier.com/). Network controllers act as configuration servers and certificate authorities for the members of networks. Controllers are located on the network by simply parsing out the first 10 digits of a network's 16-digit network ID: these are the address of the controller.
|
||||
|
||||
As of ZeroTier One version 1.2.0 this code is included in normal builds for desktop, laptop, and server (Linux, etc.) targets, allowing any device to create virtual networks without having to be rebuilt from source with special flags to enable this feature. While this does offer a convenient way to create ad-hoc networks or experiment, we recommend running a dedicated controller somewhere secure and stable for any "serious" use case.
|
||||
|
||||
Controller data is stored in JSON format under `controller.d` in the ZeroTier working directory. It can be copied, rsync'd, placed in `git`, etc. The files under `controller.d` should not be modified in place while the controller is running or data loss may result, and if they are edited directly take care not to save corrupt JSON since that can also lead to data loss when the controller is restarted. Going through the API is strongly preferred to directly modifying these files.
|
||||
|
||||
### Upgrading from Older (1.1.14 or earlier) Versions
|
||||
|
||||
Older versions of this code used a SQLite database instead of in-filesystem JSON. A migration utility called `migrate-sqlite` is included here and *must* be used to migrate this data to the new format. If the controller is started with an old `controller.db` in its working directory it will terminate after printing an error to *stderr*. This is done to prevent "surprises" for those running DIY controllers using the old code.
|
||||
|
||||
The migration tool is written in nodeJS and can be used like this:
|
||||
|
||||
cd migrate-sqlite
|
||||
npm install
|
||||
node migrate.js </path/to/controller.db> </path/to/controller.d>
|
||||
|
||||
Very old versions of nodeJS may have issues. We tested it with version 7.
|
||||
|
||||
### Scalability and Reliability
|
||||
|
||||
Controllers can in theory host up to 2^24 networks and serve many millions of devices (or more), but we recommend spreading large numbers of networks across many controllers for load balancing and fault tolerance reasons. Since the controller uses the filesystem as its data store we recommend fast filesystems and fast SSD drives for heavily loaded controllers.
|
||||
|
||||
Since ZeroTier nodes are mobile and do not need static IPs, implementing high availability fail-over for controllers is easy. Just replicate their working directories from master to backup and have something automatically fire up the backup if the master goes down. Many modern orchestration tools have built-in support for this. It would also be possible in theory to run controllers on a replicated or distributed filesystem, but we haven't tested this yet.
|
||||
|
||||
### Dockerizing Controllers
|
||||
|
||||
ZeroTier network controllers can easily be run in Docker or other container systems. Since containers do not need to actually join networks, extra privilege options like "--device=/dev/net/tun --privileged" are not needed. You'll just need to map the local JSON API port of the running controller and allow it to access the Internet (over UDP/9993 at a minimum) so things can reach and query it.
|
||||
|
||||
### Network Controller API
|
||||
|
||||
The controller API is hosted via the same JSON API endpoint that ZeroTier One uses for local control (usually at 127.0.0.1 port 9993). All controller options are routed under the `/controller` base path.
|
||||
|
||||
The controller microservice does not implement any fine-grained access control (authentication is via authtoken.secret just like the regular JSON API) or other complex mangement features. It just takes network and network member configurations and reponds to controller queries. We have an enterprise product called [ZeroTier Central](https://my.zerotier.com/) that we host as a service (and that companies can license to self-host) that does this.
|
||||
|
||||
All working network IDs on a controller must begin with the controller's ZeroTier address. The API will *allow* "foreign" networks to be added but the controller will have no way of doing anything with them since nobody will know to query it. (In the future we might support secondaries, which would make this relevant.)
|
||||
|
||||
The JSON API is *very* sensitive about types. Integers must be integers and strings strings, etc. Incorrectly typed and unrecognized fields may result in ignored fields or a 400 (bad request) error.
|
||||
|
||||
#### `/controller`
|
||||
|
||||
* Purpose: Check for controller function and return controller status
|
||||
* Methods: GET
|
||||
* Returns: { object }
|
||||
|
||||
| Field | Type | Description | Writable |
|
||||
| ------------------ | ----------- | ------------------------------------------------- | -------- |
|
||||
| controller | boolean | Always 'true' | no |
|
||||
| apiVersion | integer | Controller API version, currently 3 | no |
|
||||
| clock | integer | Current clock on controller, ms since epoch | no |
|
||||
|
||||
#### `/controller/network`
|
||||
|
||||
* Purpose: List all networks hosted by this controller
|
||||
* Methods: GET
|
||||
* Returns: [ string, ... ]
|
||||
|
||||
This returns an array of 16-digit hexadecimal network IDs.
|
||||
|
||||
#### `/controller/network/<network ID>`
|
||||
|
||||
* Purpose: Create, configure, and delete hosted networks
|
||||
* Methods: GET, POST, DELETE
|
||||
* Returns: { object }
|
||||
|
||||
By making queries to this path you can create, configure, and delete networks. DELETE is final, so don't do it unless you really mean it.
|
||||
|
||||
When POSTing new networks take care that their IDs are not in use, otherwise you may overwrite an existing one. To create a new network with a random unused ID, POST to `/controller/network/##########______`. The #'s are the controller's 10-digit ZeroTier address and they're followed by six underscores. Check the `nwid` field of the returned JSON object for your network's newly allocated ID. Subsequent POSTs to this network must refer to its actual path.
|
||||
|
||||
| Field | Type | Description | Writable |
|
||||
| --------------------- | ------------- | ------------------------------------------------- | -------- |
|
||||
| id | string | 16-digit network ID | no |
|
||||
| nwid | string | 16-digit network ID (old, but still around) | no |
|
||||
| clock | integer | Current clock, ms since epoch | no |
|
||||
| name | string | A short name for this network | YES |
|
||||
| private | boolean | Is access control enabled? | YES |
|
||||
| enableBroadcast | boolean | Ethernet ff:ff:ff:ff:ff:ff allowed? | YES |
|
||||
| allowPassiveBridging | boolean | Allow any member to bridge (very experimental) | YES |
|
||||
| v4AssignMode | object | IPv4 management and assign options (see below) | YES |
|
||||
| v6AssignMode | object | IPv6 management and assign options (see below) | YES |
|
||||
| multicastLimit | integer | Maximum recipients for a multicast packet | YES |
|
||||
| creationTime | integer | Time network was first created | no |
|
||||
| revision | integer | Network config revision counter | no |
|
||||
| authorizedMemberCount | integer | Number of authorized members (for private nets) | no |
|
||||
| activeMemberCount | integer | Number of members that appear to be online | no |
|
||||
| totalMemberCount | integer | Total known members of this network | no |
|
||||
| routes | array[object] | Managed IPv4 and IPv6 routes; see below | YES |
|
||||
| ipAssignmentPools | array[object] | IP auto-assign ranges; see below | YES |
|
||||
| rules | array[object] | Traffic rules; see below | YES |
|
||||
|
||||
Recent changes:
|
||||
|
||||
* The `ipLocalRoutes` field appeared in older versions but is no longer present. Routes will now show up in `routes`.
|
||||
* The `relays` field is gone since network preferred relays are gone. This capability is replaced by VL1 level federation ("federated roots").
|
||||
|
||||
Other important points:
|
||||
|
||||
* Networks without rules won't carry any traffic. If you don't specify any on network creation an "accept anything" rule set will automatically be added.
|
||||
* Managed IP address assignments and IP assignment pools that do not fall within a route configured in `routes` are ignored and won't be used or sent to members.
|
||||
* The default for `private` is `true` and this is probably what you want. Turning `private` off means *anyone* can join your network with only its 16-digit network ID. It's also impossible to de-authorize a member as these networks don't issue or enforce certificates. Such "party line" networks are used for decentralized app backplanes, gaming, and testing but are otherwise not common.
|
||||
|
||||
**Auto-Assign Modes:**
|
||||
|
||||
Auto assign modes (`v4AssignMode` and `v6AssignMode`) contain objects that map assignment modes to booleans.
|
||||
|
||||
For IPv4 the only valid setting is `zt` which, if true, causes IPv4 addresses to be auto-assigned from `ipAssignmentPools` to members that do not have an IPv4 assignment. Note that active bridges are exempt and will not get auto-assigned IPs since this can interfere with bridging. (You can still manually assign one if you want.)
|
||||
|
||||
IPv6 includes this option and two others: `6plane` and `rfc4193`. These assign private IPv6 addresses to each member based on a deterministic assignment scheme that allows members to emulate IPv6 NDP to skip multicast for better performance and scalability. The `rfc4193` mode gives every member a /128 on a /88 network, while `6plane` gives every member a /80 within a /40 network but uses NDP emulation to route *all* IPs under that /80 to its owner. The `6plane` mode is great for use cases like Docker since it allows every member to assign IPv6 addresses within its /80 that just work instantly and globally across the network.
|
||||
|
||||
**IP assignment pool object format:**
|
||||
|
||||
| Field | Type | Description |
|
||||
| --------------------- | ------------- | ------------------------------------------------- |
|
||||
| ipRangeStart | string | Starting IP address in range |
|
||||
| ipRangeEnd | string | Ending IP address in range (inclusive) |
|
||||
|
||||
Pools are only used if auto-assignment is on for the given address type (IPv4 or IPv6) and if the entire range falls within a managed route.
|
||||
|
||||
IPv6 ranges work just like IPv4 ranges and look like this:
|
||||
|
||||
{
|
||||
"ipRangeStart": "fd00:feed:feed:beef:0000:0000:0000:0000",
|
||||
"ipRangeEnd": "fd00:feed:feed:beef:ffff:ffff:ffff:ffff"
|
||||
}
|
||||
|
||||
(You can POST a shortened-form IPv6 address but the API will always report back un-shortened canonical form addresses.)
|
||||
|
||||
That defines a range within network `fd00:feed:feed:beef::/64` that contains up to 2^64 addresses. If an IPv6 range is large enough, the controller will assign addresses by placing each member's device ID into the address in a manner similar to the RFC4193 and 6PLANE modes. Otherwise it will assign addresses at random.
|
||||
|
||||
**Rule object format:**
|
||||
|
||||
Each rule is actually a sequence of zero or more `MATCH_` entries in the rule array followed by an `ACTION_` entry that describes what to do if all the preceding entries match. An `ACTION_` without any preceding `MATCH_` entries is always taken, so setting a single `ACTION_ACCEPT` rule yields a network that allows all traffic. If no rules are present the default action is `ACTION_DROP`.
|
||||
|
||||
Rules are evaluated in the order in which they appear in the array. There is currently a limit of 256 entries per network. Capabilities should be used if a larger and more complex rule set is needed since they allow rules to be grouped by purpose and only shipped to members that need them.
|
||||
|
||||
Each rule table entry has two common fields.
|
||||
|
||||
| Field | Type | Description |
|
||||
| --------------------- | ------------- | ------------------------------------------------- |
|
||||
| type | string | Entry type (all caps, case sensitive) |
|
||||
| not | boolean | If true, MATCHes match if they don't match |
|
||||
|
||||
The following fields may or may not be present depending on rule type:
|
||||
|
||||
| Field | Type | Description |
|
||||
| --------------------- | ------------- | ------------------------------------------------- |
|
||||
| zt | string | 10-digit hex ZeroTier address |
|
||||
| etherType | integer | Ethernet frame type |
|
||||
| mac | string | Hex MAC address (with or without :'s) |
|
||||
| ip | string | IPv4 or IPv6 address |
|
||||
| ipTos | integer | IP type of service |
|
||||
| ipProtocol | integer | IP protocol (e.g. TCP) |
|
||||
| start | integer | Start of an integer range (e.g. port range) |
|
||||
| end | integer | End of an integer range (inclusive) |
|
||||
| id | integer | Tag ID |
|
||||
| value | integer | Tag value or comparison value |
|
||||
| mask | integer | Bit mask (for characteristics flags) |
|
||||
|
||||
The entry types and their additional fields are:
|
||||
|
||||
| Entry type | Description | Fields |
|
||||
| ------------------------------- | ----------------------------------------------------------------- | -------------- |
|
||||
| `ACTION_DROP` | Drop any packets matching this rule | (none) |
|
||||
| `ACTION_ACCEPT` | Accept any packets matching this rule | (none) |
|
||||
| `ACTION_TEE` | Send a copy of this packet to a node (rule parsing continues) | `zt` |
|
||||
| `ACTION_REDIRECT` | Redirect this packet to another node | `zt` |
|
||||
| `ACTION_DEBUG_LOG` | Output debug info on match (if built with rules engine debug) | (none) |
|
||||
| `MATCH_SOURCE_ZEROTIER_ADDRESS` | Match VL1 ZeroTier address of packet sender. | `zt` |
|
||||
| `MATCH_DEST_ZEROTIER_ADDRESS` | Match VL1 ZeroTier address of recipient | `zt` |
|
||||
| `MATCH_ETHERTYPE` | Match Ethernet frame type | `etherType` |
|
||||
| `MATCH_MAC_SOURCE` | Match source Ethernet MAC address | `mac` |
|
||||
| `MATCH_MAC_DEST` | Match destination Ethernet MAC address | `mac` |
|
||||
| `MATCH_IPV4_SOURCE` | Match source IPv4 address | `ip` |
|
||||
| `MATCH_IPV4_DEST` | Match destination IPv4 address | `ip` |
|
||||
| `MATCH_IPV6_SOURCE` | Match source IPv6 address | `ip` |
|
||||
| `MATCH_IPV6_DEST` | Match destination IPv6 address | `ip` |
|
||||
| `MATCH_IP_TOS` | Match IP TOS field | `ipTos` |
|
||||
| `MATCH_IP_PROTOCOL` | Match IP protocol field | `ipProtocol` |
|
||||
| `MATCH_IP_SOURCE_PORT_RANGE` | Match a source IP port range | `start`,`end` |
|
||||
| `MATCH_IP_DEST_PORT_RANGE` | Match a destination IP port range | `start`,`end` |
|
||||
| `MATCH_CHARACTERISTICS` | Match on characteristics flags | `mask`,`value` |
|
||||
| `MATCH_FRAME_SIZE_RANGE` | Match a range of Ethernet frame sizes | `start`,`end` |
|
||||
| `MATCH_TAGS_SAMENESS` | Match if both sides' tags differ by no more than value | `id`,`value` |
|
||||
| `MATCH_TAGS_BITWISE_AND` | Match if both sides' tags AND to value | `id`,`value` |
|
||||
| `MATCH_TAGS_BITWISE_OR` | Match if both sides' tags OR to value | `id`,`value` |
|
||||
| `MATCH_TAGS_BITWISE_XOR` | Match if both sides` tags XOR to value | `id`,`value` |
|
||||
|
||||
Important notes about rules engine behavior:
|
||||
|
||||
* IPv4 and IPv6 IP address rules do not match for frames that are not IPv4 or IPv6 respectively.
|
||||
* `ACTION_DEBUG_LOG` is a no-op on nodes not built with `ZT_RULES_ENGINE_DEBUGGING` enabled (see Network.cpp). If that is enabled nodes will dump a trace of rule evaluation results to *stdout* when this action is encountered but will otherwise keep evaluating rules. This is used for basic "smoke testing" of the rules engine.
|
||||
* Multicast packets and packets destined for bridged devices treated a little differently. They are matched more than once. They are matched at the point of send with a NULL ZeroTier destination address, meaning that `MATCH_DEST_ZEROTIER_ADDRESS` is useless. That's because the true VL1 destination is not yet known. Then they are matched again for each true VL1 destination. On these later subsequent matches TEE actions are ignored and REDIRECT rules are interpreted as DROPs. This prevents multiple TEE or REDIRECT packets from being sent to third party devices.
|
||||
* Rules in capabilities are always matched as if the current device is the sender (inbound == false). A capability specifies sender side rules that can be enforced on both sides.
|
||||
|
||||
#### `/controller/network/<network ID>/member`
|
||||
|
||||
* Purpose: Get a set of all members on this network
|
||||
* Methods: GET
|
||||
* Returns: { object }
|
||||
|
||||
This returns a JSON object containing all member IDs as keys and their `memberRevisionCounter` values as values.
|
||||
|
||||
#### `/controller/network/<network ID>/active`
|
||||
|
||||
* Purpose: Get a set of all active members on this network
|
||||
* Methods: GET
|
||||
* Returns: { object }
|
||||
|
||||
This returns an object containing all currently online members and the most recent `recentLog` entries for their last request.
|
||||
|
||||
#### `/controller/network/<network ID>/member/<address>`
|
||||
|
||||
* Purpose: Create, authorize, or remove a network member
|
||||
* Methods: GET, POST, DELETE
|
||||
* Returns: { object }
|
||||
|
||||
| Field | Type | Description | Writable |
|
||||
| --------------------- | ------------- | ------------------------------------------------- | -------- |
|
||||
| id | string | Member's 10-digit ZeroTier address | no |
|
||||
| address | string | Member's 10-digit ZeroTier address | no |
|
||||
| nwid | string | 16-digit network ID | no |
|
||||
| clock | integer | Current clock, ms since epoch | no |
|
||||
| authorized | boolean | Is member authorized? (for private networks) | YES |
|
||||
| authHistory | array[object] | History of auth changes, latest at end | no |
|
||||
| activeBridge | boolean | Member is able to bridge to other Ethernet nets | YES |
|
||||
| identity | string | Member's public ZeroTier identity (if known) | no |
|
||||
| ipAssignments | array[string] | Managed IP address assignments | YES |
|
||||
| memberRevision | integer | Member revision counter | no |
|
||||
| recentLog | array[object] | Recent member activity log; see below | no |
|
||||
|
||||
Note that managed IP assignments are only used if they fall within a managed route. Otherwise they are ignored.
|
||||
|
||||
**Recent log object format:**
|
||||
|
||||
| Field | Type | Description |
|
||||
| --------------------- | ------------- | ------------------------------------------------- |
|
||||
| ts | integer | Time of request, ms since epoch |
|
||||
| auth | boolean | Was member authorized? |
|
||||
| authBy | string | How was member authorized? |
|
||||
| vMajor | integer | Client major version or -1 if unknown |
|
||||
| vMinor | integer | Client minor version or -1 if unknown |
|
||||
| vRev | integer | Client revision or -1 if unknown |
|
||||
| vProto | integer | ZeroTier protocol version reported by client |
|
||||
| fromAddr | string | Physical address if known |
|
||||
|
||||
The controller can only know a member's `fromAddr` if it's able to establish a direct path to it. Members behind very restrictive firewalls may not have this information since the controller will be receiving the member's requests by way of a relay. ZeroTier does not back-trace IP paths as packets are relayed since this would add a lot of protocol overhead.
|
||||
320
zerotierone/controller/migrate-sqlite/migrate.js
Normal file
320
zerotierone/controller/migrate-sqlite/migrate.js
Normal file
@@ -0,0 +1,320 @@
|
||||
'use strict';
|
||||
|
||||
var sqlite3 = require('sqlite3').verbose();
|
||||
var fs = require('fs');
|
||||
var async = require('async');
|
||||
|
||||
function blobToIPv4(b)
|
||||
{
|
||||
if (!b)
|
||||
return null;
|
||||
if (b.length !== 16)
|
||||
return null;
|
||||
return b.readUInt8(12).toString()+'.'+b.readUInt8(13).toString()+'.'+b.readUInt8(14).toString()+'.'+b.readUInt8(15).toString();
|
||||
}
|
||||
function blobToIPv6(b)
|
||||
{
|
||||
if (!b)
|
||||
return null;
|
||||
if (b.length !== 16)
|
||||
return null;
|
||||
var s = '';
|
||||
for(var i=0;i<16;++i) {
|
||||
var x = b.readUInt8(i).toString(16);
|
||||
if (x.length === 1)
|
||||
s += '0';
|
||||
s += x;
|
||||
if ((((i+1) & 1) === 0)&&(i !== 15))
|
||||
s += ':';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
if (process.argv.length !== 4) {
|
||||
console.log('ZeroTier Old Sqlite3 Controller DB Migration Utility');
|
||||
console.log('(c)2017 ZeroTier, Inc. [GPL3]');
|
||||
console.log('');
|
||||
console.log('Usage: node migrate.js </path/to/controller.db> </path/to/controller.d>');
|
||||
console.log('');
|
||||
console.log('The first argument must be the path to the old Sqlite3 controller.db');
|
||||
console.log('file. The second must be the path to the EMPTY controller.d database');
|
||||
console.log('directory for a new (1.1.17 or newer) controller. If this path does');
|
||||
console.log('not exist it will be created.');
|
||||
console.log('');
|
||||
console.log('WARNING: this will ONLY work correctly on a 1.1.14 controller database.');
|
||||
console.log('If your controller is old you should first upgrade to 1.1.14 and run the');
|
||||
console.log('controller so that it will brings its Sqlite3 database up to the latest');
|
||||
console.log('version before running this migration.');
|
||||
console.log('');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var oldDbPath = process.argv[2];
|
||||
var newDbPath = process.argv[3];
|
||||
|
||||
console.log('Starting migrate of "'+oldDbPath+'" to "'+newDbPath+'"...');
|
||||
console.log('');
|
||||
|
||||
var old = new sqlite3.Database(oldDbPath);
|
||||
|
||||
var networks = {};
|
||||
|
||||
var nodeIdentities = {};
|
||||
var networkCount = 0;
|
||||
var memberCount = 0;
|
||||
var routeCount = 0;
|
||||
var ipAssignmentPoolCount = 0;
|
||||
var ipAssignmentCount = 0;
|
||||
var ruleCount = 0;
|
||||
var oldSchemaVersion = -1;
|
||||
|
||||
async.series([function(nextStep) {
|
||||
|
||||
old.each('SELECT v from Config WHERE k = \'schemaVersion\'',function(err,row) {
|
||||
oldSchemaVersion = parseInt(row.v)||-1;
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
if (oldSchemaVersion !== 4) {
|
||||
console.log('FATAL: this MUST be run on a 1.1.14 controller.db! Upgrade your old');
|
||||
console.log('controller to 1.1.14 first and run it once to bring its DB up to date.');
|
||||
return process.exit(1);
|
||||
}
|
||||
|
||||
console.log('Reading networks...');
|
||||
old.each('SELECT * FROM Network',function(err,row) {
|
||||
if ((typeof row.id === 'string')&&(row.id.length === 16)) {
|
||||
var flags = parseInt(row.flags)||0;
|
||||
networks[row.id] = {
|
||||
id: row.id,
|
||||
nwid: row.id,
|
||||
objtype: 'network',
|
||||
authTokens: [],
|
||||
capabilities: [],
|
||||
creationTime: parseInt(row.creationTime)||0,
|
||||
enableBroadcast: !!row.enableBroadcast,
|
||||
ipAssignmentPools: [],
|
||||
lastModified: Date.now(),
|
||||
multicastLimit: row.multicastLimit||32,
|
||||
name: row.name||'',
|
||||
private: !!row.private,
|
||||
revision: parseInt(row.revision)||1,
|
||||
rules: [{ 'type': 'ACTION_ACCEPT' }], // populated later if there are defined rules, otherwise default is allow all
|
||||
routes: [],
|
||||
v4AssignMode: {
|
||||
'zt': ((flags & 1) !== 0)
|
||||
},
|
||||
v6AssignMode: {
|
||||
'6plane': ((flags & 4) !== 0),
|
||||
'rfc4193': ((flags & 2) !== 0),
|
||||
'zt': ((flags & 8) !== 0)
|
||||
},
|
||||
_members: {} // temporary
|
||||
};
|
||||
++networkCount;
|
||||
//console.log(networks[row.id]);
|
||||
}
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
console.log(' '+networkCount+' networks.');
|
||||
console.log('Reading network route definitions...');
|
||||
old.each('SELECT * from Route WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) {
|
||||
var network = networks[row.networkId];
|
||||
if (network) {
|
||||
var rt = {
|
||||
target: (((row.ipVersion == 4) ? blobToIPv4(row.target) : blobToIPv6(row.target))+'/'+row.targetNetmaskBits),
|
||||
via: ((row.via) ? ((row.ipVersion == 4) ? blobToIPv4(row.via) : blobToIPv6(row.via)) : null)
|
||||
};
|
||||
network.routes.push(rt);
|
||||
++routeCount;
|
||||
}
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
console.log(' '+routeCount+' routes in '+networkCount+' networks.');
|
||||
console.log('Reading IP assignment pools...');
|
||||
old.each('SELECT * FROM IpAssignmentPool WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) {
|
||||
var network = networks[row.networkId];
|
||||
if (network) {
|
||||
var p = {
|
||||
ipRangeStart: ((row.ipVersion == 4) ? blobToIPv4(row.ipRangeStart) : blobToIPv6(row.ipRangeStart)),
|
||||
ipRangeEnd: ((row.ipVersion == 4) ? blobToIPv4(row.ipRangeEnd) : blobToIPv6(row.ipRangeEnd))
|
||||
};
|
||||
network.ipAssignmentPools.push(p);
|
||||
++ipAssignmentPoolCount;
|
||||
}
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
console.log(' '+ipAssignmentPoolCount+' IP assignment pools in '+networkCount+' networks.');
|
||||
console.log('Reading known node identities...');
|
||||
old.each('SELECT * FROM Node',function(err,row) {
|
||||
nodeIdentities[row.id] = row.identity;
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
console.log(' '+Object.keys(nodeIdentities).length+' known identities.');
|
||||
console.log('Reading network members...');
|
||||
old.each('SELECT * FROM Member',function(err,row) {
|
||||
var network = networks[row.networkId];
|
||||
if (network) {
|
||||
network._members[row.nodeId] = {
|
||||
id: row.nodeId,
|
||||
address: row.nodeId,
|
||||
objtype: 'member',
|
||||
authorized: !!row.authorized,
|
||||
activeBridge: !!row.activeBridge,
|
||||
authHistory: [],
|
||||
capabilities: [],
|
||||
creationTime: 0,
|
||||
identity: nodeIdentities[row.nodeId]||null,
|
||||
ipAssignments: [],
|
||||
lastAuthorizedTime: (row.authorized) ? Date.now() : 0,
|
||||
lastDeauthorizedTime: (row.authorized) ? 0 : Date.now(),
|
||||
lastModified: Date.now(),
|
||||
lastRequestMetaData: '',
|
||||
noAutoAssignIps: false,
|
||||
nwid: row.networkId,
|
||||
revision: parseInt(row.memberRevision)||1,
|
||||
tags: [],
|
||||
recentLog: []
|
||||
};
|
||||
++memberCount;
|
||||
//console.log(network._members[row.nodeId]);
|
||||
}
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
console.log(' '+memberCount+' members of '+networkCount+' networks.');
|
||||
console.log('Reading static IP assignments...');
|
||||
old.each('SELECT * FROM IpAssignment WHERE ipVersion = 4 OR ipVersion = 6',function(err,row) {
|
||||
var network = networks[row.networkId];
|
||||
if (network) {
|
||||
var member = network._members[row.nodeId];
|
||||
if ((member)&&((member.authorized)||(!network['private']))) { // don't mirror assignments to unauthorized members to avoid conflicts
|
||||
if (row.ipVersion == 4) {
|
||||
member.ipAssignments.push(blobToIPv4(row.ip));
|
||||
++ipAssignmentCount;
|
||||
} else if (row.ipVersion == 6) {
|
||||
member.ipAssignments.push(blobToIPv6(row.ip));
|
||||
++ipAssignmentCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
},nextStep);
|
||||
|
||||
},function(nextStep) {
|
||||
|
||||
// Old versions only supported Ethertype whitelisting, so that's
|
||||
// all we mirror forward. The other fields were always unused.
|
||||
|
||||
console.log(' '+ipAssignmentCount+' IP assignments for '+memberCount+' authorized members of '+networkCount+' networks.');
|
||||
console.log('Reading allowed Ethernet types (old basic rules)...');
|
||||
var etherTypesByNetwork = {};
|
||||
old.each('SELECT DISTINCT networkId,ruleNo,etherType FROM Rule WHERE "action" = \'accept\'',function(err,row) {
|
||||
if (row.networkId in networks) {
|
||||
var et = parseInt(row.etherType)||0;
|
||||
var ets = etherTypesByNetwork[row.networkId];
|
||||
if (!ets)
|
||||
etherTypesByNetwork[row.networkId] = [ et ];
|
||||
else ets.push(et);
|
||||
}
|
||||
},function(err) {
|
||||
if (err) return nextStep(err);
|
||||
for(var nwid in etherTypesByNetwork) {
|
||||
var ets = etherTypesByNetwork[nwid].sort();
|
||||
var network = networks[nwid];
|
||||
if (network) {
|
||||
var rules = [];
|
||||
if (ets.indexOf(0) >= 0) {
|
||||
// If 0 is in the list, all Ethernet types are allowed so we accept all.
|
||||
rules.push({ 'type': 'ACTION_ACCEPT' });
|
||||
} else {
|
||||
// Otherwise we whitelist.
|
||||
for(var i=0;i<ets.length;++i) {
|
||||
rules.push({
|
||||
'etherType': ets[i],
|
||||
'not': true,
|
||||
'or': false,
|
||||
'type': 'MATCH_ETHERTYPE'
|
||||
});
|
||||
}
|
||||
rules.push({ 'type': 'ACTION_DROP' });
|
||||
rules.push({ 'type': 'ACTION_ACCEPT' });
|
||||
}
|
||||
network.rules = rules;
|
||||
++ruleCount;
|
||||
}
|
||||
}
|
||||
return nextStep(null);
|
||||
});
|
||||
|
||||
}],function(err) {
|
||||
|
||||
if (err) {
|
||||
console.log('FATAL: '+err.toString());
|
||||
return process.exit(1);
|
||||
}
|
||||
|
||||
console.log(' '+ruleCount+' ethernet type whitelists converted to new format rules.');
|
||||
old.close();
|
||||
console.log('Done reading and converting Sqlite3 database! Writing JSONDB files...');
|
||||
|
||||
try {
|
||||
fs.mkdirSync(newDbPath,0o700);
|
||||
} catch (e) {}
|
||||
var nwBase = newDbPath+'/network';
|
||||
try {
|
||||
fs.mkdirSync(nwBase,0o700);
|
||||
} catch (e) {}
|
||||
nwBase = nwBase + '/';
|
||||
var nwids = Object.keys(networks).sort();
|
||||
var fileCount = 0;
|
||||
for(var ni=0;ni<nwids.length;++ni) {
|
||||
var network = networks[nwids[ni]];
|
||||
|
||||
var mids = Object.keys(network._members).sort();
|
||||
if (mids.length > 0) {
|
||||
try {
|
||||
fs.mkdirSync(nwBase+network.id);
|
||||
} catch (e) {}
|
||||
var mbase = nwBase+network.id+'/member';
|
||||
try {
|
||||
fs.mkdirSync(mbase,0o700);
|
||||
} catch (e) {}
|
||||
mbase = mbase + '/';
|
||||
|
||||
for(var mi=0;mi<mids.length;++mi) {
|
||||
var member = network._members[mids[mi]];
|
||||
fs.writeFileSync(mbase+member.id+'.json',JSON.stringify(member,null,1),{ mode: 0o600 });
|
||||
++fileCount;
|
||||
//console.log(mbase+member.id+'.json');
|
||||
}
|
||||
}
|
||||
|
||||
delete network._members; // temporary field, not part of actual JSONDB, so don't write
|
||||
fs.writeFileSync(nwBase+network.id+'.json',JSON.stringify(network,null,1),{ mode: 0o600 });
|
||||
++fileCount;
|
||||
//console.log(nwBase+network.id+'.json');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('SUCCESS! Wrote '+fileCount+' JSONDB files.');
|
||||
|
||||
console.log('');
|
||||
console.log('You should still inspect the new DB before going live. Also be sure');
|
||||
console.log('to "chown -R" and "chgrp -R" the new DB to the user and group under');
|
||||
console.log('which the ZeroTier One instance acting as controller will be running.');
|
||||
console.log('The controller must be able to read and write the DB, of course.');
|
||||
console.log('');
|
||||
console.log('Have fun!');
|
||||
|
||||
return process.exit(0);
|
||||
});
|
||||
15
zerotierone/controller/migrate-sqlite/package.json
Normal file
15
zerotierone/controller/migrate-sqlite/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "migrate-sqlite",
|
||||
"version": "1.0.0",
|
||||
"description": "Migrate old SQLite to new JSON filesystem DB for ZeroTier network controller",
|
||||
"main": "migrate.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Adam Ierymenko <adam.ierymenko@zerotier.com>",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"async": "^2.1.4",
|
||||
"sqlite3": "^3.1.8"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
'\" -*- coding: utf-8 -*-
|
||||
BIN
zerotierone/ext/bin/tap-windows-ndis6/x64/zttap300.cat
Normal file
BIN
zerotierone/ext/bin/tap-windows-ndis6/x64/zttap300.cat
Normal file
Binary file not shown.
143
zerotierone/ext/bin/tap-windows-ndis6/x64/zttap300.inf
Normal file
143
zerotierone/ext/bin/tap-windows-ndis6/x64/zttap300.inf
Normal file
@@ -0,0 +1,143 @@
|
||||
;
|
||||
; ZeroTier One Virtual Network Port NDIS6 Driver
|
||||
;
|
||||
; Based on the OpenVPN tap-windows6 driver version 9.21.1 git
|
||||
; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3.
|
||||
; See: https://github.com/OpenVPN/tap-windows6
|
||||
;
|
||||
; Modified by ZeroTier, Inc. - https://www.zerotier.com/
|
||||
;
|
||||
; (1) Comment out 'tun' functionality and related features such as DHCP
|
||||
; emulation, since we don't use any of that. Just want straight 'tap'.
|
||||
; (2) Added custom IOCTL to enumerate L2 multicast memberships.
|
||||
; (3) Increase maximum number of multicast memberships to 128.
|
||||
; (4) Set default and max device MTU to 2800.
|
||||
; (5) Rename/rebrand driver as ZeroTier network port driver.
|
||||
;
|
||||
; Original copyright below. Modifications released under GPLv2 as well.
|
||||
;
|
||||
; ****************************************************************************
|
||||
; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. *
|
||||
; * This program is free software; you can redistribute it and/or modify *
|
||||
; * it under the terms of the GNU General Public License version 2 *
|
||||
; * as published by the Free Software Foundation. *
|
||||
; ****************************************************************************
|
||||
;
|
||||
|
||||
[Version]
|
||||
Signature = "$Windows NT$"
|
||||
CatalogFile = zttap300.cat
|
||||
ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
|
||||
Provider = %Provider%
|
||||
Class = Net
|
||||
DriverVer=08/13/2015,6.2.9200.20557
|
||||
|
||||
[Strings]
|
||||
DeviceDescription = "ZeroTier One Virtual Port"
|
||||
Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat.
|
||||
|
||||
; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back!
|
||||
[Manufacturer]
|
||||
%Provider%=zttap300,NTamd64
|
||||
|
||||
[zttap300]
|
||||
%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
|
||||
%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy
|
||||
|
||||
[zttap300.NTamd64]
|
||||
%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
|
||||
%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy
|
||||
|
||||
;----------------- Characteristics ------------
|
||||
; NCF_PHYSICAL = 0x04
|
||||
; NCF_VIRTUAL = 0x01
|
||||
; NCF_SOFTWARE_ENUMERATED = 0x02
|
||||
; NCF_HIDDEN = 0x08
|
||||
; NCF_NO_SERVICE = 0x10
|
||||
; NCF_HAS_UI = 0x80
|
||||
;----------------- Characteristics ------------
|
||||
[zttap300.ndi]
|
||||
CopyFiles = zttap300.driver, zttap300.files
|
||||
AddReg = zttap300.reg
|
||||
AddReg = zttap300.params.reg
|
||||
Characteristics = 0x81
|
||||
*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD
|
||||
*MediaType = 0x0 ; NdisMedium802_3
|
||||
*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3
|
||||
|
||||
[zttap300.ndi.Services]
|
||||
AddService = zttap300, 2, zttap300.service
|
||||
|
||||
[zttap300.reg]
|
||||
HKR, Ndi, Service, 0, "zttap300"
|
||||
HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows.
|
||||
HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
|
||||
HKR, , Manufacturer, 0, "%Provider%"
|
||||
HKR, , ProductName, 0, "%DeviceDescription%"
|
||||
|
||||
[zttap300.params.reg]
|
||||
HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
|
||||
HKR, Ndi\params\MTU, Type, 0, "int"
|
||||
HKR, Ndi\params\MTU, Default, 0, "2800"
|
||||
HKR, Ndi\params\MTU, Optional, 0, "0"
|
||||
HKR, Ndi\params\MTU, Min, 0, "100"
|
||||
HKR, Ndi\params\MTU, Max, 0, "2800"
|
||||
HKR, Ndi\params\MTU, Step, 0, "1"
|
||||
HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status"
|
||||
HKR, Ndi\params\MediaStatus, Type, 0, "enum"
|
||||
HKR, Ndi\params\MediaStatus, Default, 0, "0"
|
||||
HKR, Ndi\params\MediaStatus, Optional, 0, "0"
|
||||
HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled"
|
||||
HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected"
|
||||
HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address"
|
||||
HKR, Ndi\params\MAC, Type, 0, "edit"
|
||||
HKR, Ndi\params\MAC, Optional, 0, "1"
|
||||
HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access"
|
||||
HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum"
|
||||
HKR, Ndi\params\AllowNonAdmin, Default, 0, "0"
|
||||
HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0"
|
||||
HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed"
|
||||
HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed"
|
||||
|
||||
;---------- Service Type -------------
|
||||
; SERVICE_KERNEL_DRIVER = 0x01
|
||||
; SERVICE_WIN32_OWN_PROCESS = 0x10
|
||||
;---------- Service Type -------------
|
||||
|
||||
;---------- Start Mode ---------------
|
||||
; SERVICE_BOOT_START = 0x0
|
||||
; SERVICE_SYSTEM_START = 0x1
|
||||
; SERVICE_AUTO_START = 0x2
|
||||
; SERVICE_DEMAND_START = 0x3
|
||||
; SERVICE_DISABLED = 0x4
|
||||
;---------- Start Mode ---------------
|
||||
|
||||
[zttap300.service]
|
||||
DisplayName = %DeviceDescription%
|
||||
ServiceType = 1
|
||||
StartType = 3
|
||||
ErrorControl = 1
|
||||
LoadOrderGroup = NDIS
|
||||
ServiceBinary = %12%\zttap300.sys
|
||||
|
||||
;----------------- Copy Flags ------------
|
||||
; COPYFLG_NOSKIP = 0x02
|
||||
; COPYFLG_NOVERSIONCHECK = 0x04
|
||||
;----------------- Copy Flags ------------
|
||||
|
||||
[SourceDisksNames]
|
||||
1 = %DeviceDescription%, zttap300.sys
|
||||
|
||||
[SourceDisksFiles]
|
||||
zttap300.sys = 1
|
||||
|
||||
[DestinationDirs]
|
||||
zttap300.files = 11
|
||||
zttap300.driver = 12
|
||||
|
||||
[zttap300.files]
|
||||
;
|
||||
|
||||
[zttap300.driver]
|
||||
zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
|
||||
|
||||
BIN
zerotierone/ext/bin/tap-windows-ndis6/x64/zttap300.sys
Normal file
BIN
zerotierone/ext/bin/tap-windows-ndis6/x64/zttap300.sys
Normal file
Binary file not shown.
BIN
zerotierone/ext/bin/tap-windows-ndis6/x86/zttap300.cat
Normal file
BIN
zerotierone/ext/bin/tap-windows-ndis6/x86/zttap300.cat
Normal file
Binary file not shown.
143
zerotierone/ext/bin/tap-windows-ndis6/x86/zttap300.inf
Normal file
143
zerotierone/ext/bin/tap-windows-ndis6/x86/zttap300.inf
Normal file
@@ -0,0 +1,143 @@
|
||||
;
|
||||
; ZeroTier One Virtual Network Port NDIS6 Driver
|
||||
;
|
||||
; Based on the OpenVPN tap-windows6 driver version 9.21.1 git
|
||||
; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3.
|
||||
; See: https://github.com/OpenVPN/tap-windows6
|
||||
;
|
||||
; Modified by ZeroTier, Inc. - https://www.zerotier.com/
|
||||
;
|
||||
; (1) Comment out 'tun' functionality and related features such as DHCP
|
||||
; emulation, since we don't use any of that. Just want straight 'tap'.
|
||||
; (2) Added custom IOCTL to enumerate L2 multicast memberships.
|
||||
; (3) Increase maximum number of multicast memberships to 128.
|
||||
; (4) Set default and max device MTU to 2800.
|
||||
; (5) Rename/rebrand driver as ZeroTier network port driver.
|
||||
;
|
||||
; Original copyright below. Modifications released under GPLv2 as well.
|
||||
;
|
||||
; ****************************************************************************
|
||||
; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. *
|
||||
; * This program is free software; you can redistribute it and/or modify *
|
||||
; * it under the terms of the GNU General Public License version 2 *
|
||||
; * as published by the Free Software Foundation. *
|
||||
; ****************************************************************************
|
||||
;
|
||||
|
||||
[Version]
|
||||
Signature = "$Windows NT$"
|
||||
CatalogFile = zttap300.cat
|
||||
ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
|
||||
Provider = %Provider%
|
||||
Class = Net
|
||||
DriverVer=08/13/2015,6.2.9200.20557
|
||||
|
||||
[Strings]
|
||||
DeviceDescription = "ZeroTier One Virtual Port"
|
||||
Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat.
|
||||
|
||||
; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back!
|
||||
[Manufacturer]
|
||||
%Provider%=zttap300,NTamd64
|
||||
|
||||
[zttap300]
|
||||
%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
|
||||
%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy
|
||||
|
||||
[zttap300.NTamd64]
|
||||
%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
|
||||
%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy
|
||||
|
||||
;----------------- Characteristics ------------
|
||||
; NCF_PHYSICAL = 0x04
|
||||
; NCF_VIRTUAL = 0x01
|
||||
; NCF_SOFTWARE_ENUMERATED = 0x02
|
||||
; NCF_HIDDEN = 0x08
|
||||
; NCF_NO_SERVICE = 0x10
|
||||
; NCF_HAS_UI = 0x80
|
||||
;----------------- Characteristics ------------
|
||||
[zttap300.ndi]
|
||||
CopyFiles = zttap300.driver, zttap300.files
|
||||
AddReg = zttap300.reg
|
||||
AddReg = zttap300.params.reg
|
||||
Characteristics = 0x81
|
||||
*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD
|
||||
*MediaType = 0x0 ; NdisMedium802_3
|
||||
*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3
|
||||
|
||||
[zttap300.ndi.Services]
|
||||
AddService = zttap300, 2, zttap300.service
|
||||
|
||||
[zttap300.reg]
|
||||
HKR, Ndi, Service, 0, "zttap300"
|
||||
HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows.
|
||||
HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
|
||||
HKR, , Manufacturer, 0, "%Provider%"
|
||||
HKR, , ProductName, 0, "%DeviceDescription%"
|
||||
|
||||
[zttap300.params.reg]
|
||||
HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
|
||||
HKR, Ndi\params\MTU, Type, 0, "int"
|
||||
HKR, Ndi\params\MTU, Default, 0, "2800"
|
||||
HKR, Ndi\params\MTU, Optional, 0, "0"
|
||||
HKR, Ndi\params\MTU, Min, 0, "100"
|
||||
HKR, Ndi\params\MTU, Max, 0, "2800"
|
||||
HKR, Ndi\params\MTU, Step, 0, "1"
|
||||
HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status"
|
||||
HKR, Ndi\params\MediaStatus, Type, 0, "enum"
|
||||
HKR, Ndi\params\MediaStatus, Default, 0, "0"
|
||||
HKR, Ndi\params\MediaStatus, Optional, 0, "0"
|
||||
HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled"
|
||||
HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected"
|
||||
HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address"
|
||||
HKR, Ndi\params\MAC, Type, 0, "edit"
|
||||
HKR, Ndi\params\MAC, Optional, 0, "1"
|
||||
HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access"
|
||||
HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum"
|
||||
HKR, Ndi\params\AllowNonAdmin, Default, 0, "0"
|
||||
HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0"
|
||||
HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed"
|
||||
HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed"
|
||||
|
||||
;---------- Service Type -------------
|
||||
; SERVICE_KERNEL_DRIVER = 0x01
|
||||
; SERVICE_WIN32_OWN_PROCESS = 0x10
|
||||
;---------- Service Type -------------
|
||||
|
||||
;---------- Start Mode ---------------
|
||||
; SERVICE_BOOT_START = 0x0
|
||||
; SERVICE_SYSTEM_START = 0x1
|
||||
; SERVICE_AUTO_START = 0x2
|
||||
; SERVICE_DEMAND_START = 0x3
|
||||
; SERVICE_DISABLED = 0x4
|
||||
;---------- Start Mode ---------------
|
||||
|
||||
[zttap300.service]
|
||||
DisplayName = %DeviceDescription%
|
||||
ServiceType = 1
|
||||
StartType = 3
|
||||
ErrorControl = 1
|
||||
LoadOrderGroup = NDIS
|
||||
ServiceBinary = %12%\zttap300.sys
|
||||
|
||||
;----------------- Copy Flags ------------
|
||||
; COPYFLG_NOSKIP = 0x02
|
||||
; COPYFLG_NOVERSIONCHECK = 0x04
|
||||
;----------------- Copy Flags ------------
|
||||
|
||||
[SourceDisksNames]
|
||||
1 = %DeviceDescription%, zttap300.sys
|
||||
|
||||
[SourceDisksFiles]
|
||||
zttap300.sys = 1
|
||||
|
||||
[DestinationDirs]
|
||||
zttap300.files = 11
|
||||
zttap300.driver = 12
|
||||
|
||||
[zttap300.files]
|
||||
;
|
||||
|
||||
[zttap300.driver]
|
||||
zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
|
||||
|
||||
BIN
zerotierone/ext/bin/tap-windows-ndis6/x86/zttap300.sys
Normal file
BIN
zerotierone/ext/bin/tap-windows-ndis6/x86/zttap300.sys
Normal file
Binary file not shown.
246
zerotierone/ext/http-parser/README.md
Normal file
246
zerotierone/ext/http-parser/README.md
Normal file
@@ -0,0 +1,246 @@
|
||||
HTTP Parser
|
||||
===========
|
||||
|
||||
[](https://travis-ci.org/nodejs/http-parser)
|
||||
|
||||
This is a parser for HTTP messages written in C. It parses both requests and
|
||||
responses. The parser is designed to be used in performance HTTP
|
||||
applications. It does not make any syscalls nor allocations, it does not
|
||||
buffer data, it can be interrupted at anytime. Depending on your
|
||||
architecture, it only requires about 40 bytes of data per message
|
||||
stream (in a web server that is per connection).
|
||||
|
||||
Features:
|
||||
|
||||
* No dependencies
|
||||
* Handles persistent streams (keep-alive).
|
||||
* Decodes chunked encoding.
|
||||
* Upgrade support
|
||||
* Defends against buffer overflow attacks.
|
||||
|
||||
The parser extracts the following information from HTTP messages:
|
||||
|
||||
* Header fields and values
|
||||
* Content-Length
|
||||
* Request method
|
||||
* Response status code
|
||||
* Transfer-Encoding
|
||||
* HTTP version
|
||||
* Request URL
|
||||
* Message body
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
One `http_parser` object is used per TCP connection. Initialize the struct
|
||||
using `http_parser_init()` and set the callbacks. That might look something
|
||||
like this for a request parser:
|
||||
```c
|
||||
http_parser_settings settings;
|
||||
settings.on_url = my_url_callback;
|
||||
settings.on_header_field = my_header_field_callback;
|
||||
/* ... */
|
||||
|
||||
http_parser *parser = malloc(sizeof(http_parser));
|
||||
http_parser_init(parser, HTTP_REQUEST);
|
||||
parser->data = my_socket;
|
||||
```
|
||||
|
||||
When data is received on the socket execute the parser and check for errors.
|
||||
|
||||
```c
|
||||
size_t len = 80*1024, nparsed;
|
||||
char buf[len];
|
||||
ssize_t recved;
|
||||
|
||||
recved = recv(fd, buf, len, 0);
|
||||
|
||||
if (recved < 0) {
|
||||
/* Handle error. */
|
||||
}
|
||||
|
||||
/* Start up / continue the parser.
|
||||
* Note we pass recved==0 to signal that EOF has been received.
|
||||
*/
|
||||
nparsed = http_parser_execute(parser, &settings, buf, recved);
|
||||
|
||||
if (parser->upgrade) {
|
||||
/* handle new protocol */
|
||||
} else if (nparsed != recved) {
|
||||
/* Handle error. Usually just close the connection. */
|
||||
}
|
||||
```
|
||||
|
||||
HTTP needs to know where the end of the stream is. For example, sometimes
|
||||
servers send responses without Content-Length and expect the client to
|
||||
consume input (for the body) until EOF. To tell http_parser about EOF, give
|
||||
`0` as the fourth parameter to `http_parser_execute()`. Callbacks and errors
|
||||
can still be encountered during an EOF, so one must still be prepared
|
||||
to receive them.
|
||||
|
||||
Scalar valued message information such as `status_code`, `method`, and the
|
||||
HTTP version are stored in the parser structure. This data is only
|
||||
temporally stored in `http_parser` and gets reset on each new message. If
|
||||
this information is needed later, copy it out of the structure during the
|
||||
`headers_complete` callback.
|
||||
|
||||
The parser decodes the transfer-encoding for both requests and responses
|
||||
transparently. That is, a chunked encoding is decoded before being sent to
|
||||
the on_body callback.
|
||||
|
||||
|
||||
The Special Problem of Upgrade
|
||||
------------------------------
|
||||
|
||||
HTTP supports upgrading the connection to a different protocol. An
|
||||
increasingly common example of this is the WebSocket protocol which sends
|
||||
a request like
|
||||
|
||||
GET /demo HTTP/1.1
|
||||
Upgrade: WebSocket
|
||||
Connection: Upgrade
|
||||
Host: example.com
|
||||
Origin: http://example.com
|
||||
WebSocket-Protocol: sample
|
||||
|
||||
followed by non-HTTP data.
|
||||
|
||||
(See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the
|
||||
WebSocket protocol.)
|
||||
|
||||
To support this, the parser will treat this as a normal HTTP message without a
|
||||
body, issuing both on_headers_complete and on_message_complete callbacks. However
|
||||
http_parser_execute() will stop parsing at the end of the headers and return.
|
||||
|
||||
The user is expected to check if `parser->upgrade` has been set to 1 after
|
||||
`http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied
|
||||
offset by the return value of `http_parser_execute()`.
|
||||
|
||||
|
||||
Callbacks
|
||||
---------
|
||||
|
||||
During the `http_parser_execute()` call, the callbacks set in
|
||||
`http_parser_settings` will be executed. The parser maintains state and
|
||||
never looks behind, so buffering the data is not necessary. If you need to
|
||||
save certain data for later usage, you can do that from the callbacks.
|
||||
|
||||
There are two types of callbacks:
|
||||
|
||||
* notification `typedef int (*http_cb) (http_parser*);`
|
||||
Callbacks: on_message_begin, on_headers_complete, on_message_complete.
|
||||
* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);`
|
||||
Callbacks: (requests only) on_url,
|
||||
(common) on_header_field, on_header_value, on_body;
|
||||
|
||||
Callbacks must return 0 on success. Returning a non-zero value indicates
|
||||
error to the parser, making it exit immediately.
|
||||
|
||||
For cases where it is necessary to pass local information to/from a callback,
|
||||
the `http_parser` object's `data` field can be used.
|
||||
An example of such a case is when using threads to handle a socket connection,
|
||||
parse a request, and then give a response over that socket. By instantiation
|
||||
of a thread-local struct containing relevant data (e.g. accepted socket,
|
||||
allocated memory for callbacks to write into, etc), a parser's callbacks are
|
||||
able to communicate data between the scope of the thread and the scope of the
|
||||
callback in a threadsafe manner. This allows http-parser to be used in
|
||||
multi-threaded contexts.
|
||||
|
||||
Example:
|
||||
```c
|
||||
typedef struct {
|
||||
socket_t sock;
|
||||
void* buffer;
|
||||
int buf_len;
|
||||
} custom_data_t;
|
||||
|
||||
|
||||
int my_url_callback(http_parser* parser, const char *at, size_t length) {
|
||||
/* access to thread local custom_data_t struct.
|
||||
Use this access save parsed data for later use into thread local
|
||||
buffer, or communicate over socket
|
||||
*/
|
||||
parser->data;
|
||||
...
|
||||
return 0;
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
void http_parser_thread(socket_t sock) {
|
||||
int nparsed = 0;
|
||||
/* allocate memory for user data */
|
||||
custom_data_t *my_data = malloc(sizeof(custom_data_t));
|
||||
|
||||
/* some information for use by callbacks.
|
||||
* achieves thread -> callback information flow */
|
||||
my_data->sock = sock;
|
||||
|
||||
/* instantiate a thread-local parser */
|
||||
http_parser *parser = malloc(sizeof(http_parser));
|
||||
http_parser_init(parser, HTTP_REQUEST); /* initialise parser */
|
||||
/* this custom data reference is accessible through the reference to the
|
||||
parser supplied to callback functions */
|
||||
parser->data = my_data;
|
||||
|
||||
http_parser_settings settings; /* set up callbacks */
|
||||
settings.on_url = my_url_callback;
|
||||
|
||||
/* execute parser */
|
||||
nparsed = http_parser_execute(parser, &settings, buf, recved);
|
||||
|
||||
...
|
||||
/* parsed information copied from callback.
|
||||
can now perform action on data copied into thread-local memory from callbacks.
|
||||
achieves callback -> thread information flow */
|
||||
my_data->buffer;
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In case you parse HTTP message in chunks (i.e. `read()` request line
|
||||
from socket, parse, read half headers, parse, etc) your data callbacks
|
||||
may be called more than once. Http-parser guarantees that data pointer is only
|
||||
valid for the lifetime of callback. You can also `read()` into a heap allocated
|
||||
buffer to avoid copying memory around if this fits your application.
|
||||
|
||||
Reading headers may be a tricky task if you read/parse headers partially.
|
||||
Basically, you need to remember whether last header callback was field or value
|
||||
and apply the following logic:
|
||||
|
||||
(on_header_field and on_header_value shortened to on_h_*)
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| State (prev. callback) | Callback | Description/action |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| nothing (first call) | on_h_field | Allocate new buffer and copy callback data |
|
||||
| | | into it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| value | on_h_field | New header started. |
|
||||
| | | Copy current name,value buffers to headers |
|
||||
| | | list and allocate new buffer for new name |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| field | on_h_field | Previous name continues. Reallocate name |
|
||||
| | | buffer and append callback data to it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| field | on_h_value | Value for current header started. Allocate |
|
||||
| | | new buffer and copy callback data to it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| value | on_h_value | Value continues. Reallocate value buffer |
|
||||
| | | and append callback data to it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
|
||||
|
||||
Parsing URLs
|
||||
------------
|
||||
|
||||
A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`.
|
||||
Users of this library may wish to use it to parse URLs constructed from
|
||||
consecutive `on_url` callbacks.
|
||||
|
||||
See examples of reading in headers:
|
||||
|
||||
* [partial example](http://gist.github.com/155877) in C
|
||||
* [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C
|
||||
* [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript
|
||||
22
zerotierone/ext/json/LICENSE.MIT
Normal file
22
zerotierone/ext/json/LICENSE.MIT
Normal file
@@ -0,0 +1,22 @@
|
||||
The library is licensed under the MIT License
|
||||
<http://opensource.org/licenses/MIT>:
|
||||
|
||||
Copyright (c) 2013-2016 Niels Lohmann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
538
zerotierone/ext/json/README.md
Normal file
538
zerotierone/ext/json/README.md
Normal file
@@ -0,0 +1,538 @@
|
||||
[](https://github.com/nlohmann/json/releases)
|
||||
|
||||
[](https://travis-ci.org/nlohmann/json)
|
||||
[](https://ci.appveyor.com/project/nlohmann/json)
|
||||
[](https://coveralls.io/r/nlohmann/json)
|
||||
[](http://melpon.org/wandbox/permlink/fsf5FqYe6GoX68W6)
|
||||
[](http://nlohmann.github.io/json)
|
||||
[](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)
|
||||
[](https://github.com/nlohmann/json/releases)
|
||||
[](http://github.com/nlohmann/json/issues)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/289)
|
||||
|
||||
## Design goals
|
||||
|
||||
There are myriads of [JSON](http://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals:
|
||||
|
||||
- **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you'll know what I mean.
|
||||
|
||||
- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/src/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings.
|
||||
|
||||
- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/blob/master/test/src/unit.cpp) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) that there are no memory leaks. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289).
|
||||
|
||||
Other aspects were not so important to us:
|
||||
|
||||
- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs.
|
||||
|
||||
- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) may be even faster (but would consist of more files which makes the integration harder).
|
||||
|
||||
See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information.
|
||||
|
||||
|
||||
## Integration
|
||||
|
||||
The single required source, file `json.hpp` is in the `src` directory or [released here](https://github.com/nlohmann/json/releases). All you need to do is add
|
||||
|
||||
```cpp
|
||||
#include "json.hpp"
|
||||
|
||||
// for convenience
|
||||
using json = nlohmann::json;
|
||||
```
|
||||
|
||||
to the files you want to use JSON objects. That's it. Do not forget to set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang).
|
||||
|
||||
:beer: If you are using OS X and [Homebrew](http://brew.sh), just type `brew tap nlohmann/json` and `brew install nlohmann_json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann_json --HEAD`.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Here are some examples to give you an idea how to use the class.
|
||||
|
||||
Assume you want to create the JSON object
|
||||
|
||||
```json
|
||||
{
|
||||
"pi": 3.141,
|
||||
"happy": true,
|
||||
"name": "Niels",
|
||||
"nothing": null,
|
||||
"answer": {
|
||||
"everything": 42
|
||||
},
|
||||
"list": [1, 0, 2],
|
||||
"object": {
|
||||
"currency": "USD",
|
||||
"value": 42.99
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With the JSON class, you could write:
|
||||
|
||||
```cpp
|
||||
// create an empty structure (null)
|
||||
json j;
|
||||
|
||||
// add a number that is stored as double (note the implicit conversion of j to an object)
|
||||
j["pi"] = 3.141;
|
||||
|
||||
// add a Boolean that is stored as bool
|
||||
j["happy"] = true;
|
||||
|
||||
// add a string that is stored as std::string
|
||||
j["name"] = "Niels";
|
||||
|
||||
// add another null object by passing nullptr
|
||||
j["nothing"] = nullptr;
|
||||
|
||||
// add an object inside the object
|
||||
j["answer"]["everything"] = 42;
|
||||
|
||||
// add an array that is stored as std::vector (using an initializer list)
|
||||
j["list"] = { 1, 0, 2 };
|
||||
|
||||
// add another object (using an initializer list of pairs)
|
||||
j["object"] = { {"currency", "USD"}, {"value", 42.99} };
|
||||
|
||||
// instead, you could also write (which looks very similar to the JSON above)
|
||||
json j2 = {
|
||||
{"pi", 3.141},
|
||||
{"happy", true},
|
||||
{"name", "Niels"},
|
||||
{"nothing", nullptr},
|
||||
{"answer", {
|
||||
{"everything", 42}
|
||||
}},
|
||||
{"list", {1, 0, 2}},
|
||||
{"object", {
|
||||
{"currency", "USD"},
|
||||
{"value", 42.99}
|
||||
}}
|
||||
};
|
||||
```
|
||||
|
||||
Note that in all these cases, you never need to "tell" the compiler which JSON value you want to use. If you want to be explicit or express some edge cases, the functions `json::array` and `json::object` will help:
|
||||
|
||||
```cpp
|
||||
// a way to express the empty array []
|
||||
json empty_array_explicit = json::array();
|
||||
|
||||
// ways to express the empty object {}
|
||||
json empty_object_implicit = json({});
|
||||
json empty_object_explicit = json::object();
|
||||
|
||||
// a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
|
||||
json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) };
|
||||
```
|
||||
|
||||
|
||||
### Serialization / Deserialization
|
||||
|
||||
You can create an object (deserialization) by appending `_json` to a string literal:
|
||||
|
||||
```cpp
|
||||
// create object from string literal
|
||||
json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
|
||||
|
||||
// or even nicer with a raw string literal
|
||||
auto j2 = R"(
|
||||
{
|
||||
"happy": true,
|
||||
"pi": 3.141
|
||||
}
|
||||
)"_json;
|
||||
|
||||
// or explicitly
|
||||
auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
|
||||
```
|
||||
|
||||
You can also get a string representation (serialize):
|
||||
|
||||
```cpp
|
||||
// explicit conversion to string
|
||||
std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141}
|
||||
|
||||
// serialization with pretty printing
|
||||
// pass in the amount of spaces to indent
|
||||
std::cout << j.dump(4) << std::endl;
|
||||
// {
|
||||
// "happy": true,
|
||||
// "pi": 3.141
|
||||
// }
|
||||
```
|
||||
|
||||
You can also use streams to serialize and deserialize:
|
||||
|
||||
```cpp
|
||||
// deserialize from standard input
|
||||
json j;
|
||||
std::cin >> j;
|
||||
|
||||
// serialize to standard output
|
||||
std::cout << j;
|
||||
|
||||
// the setw manipulator was overloaded to set the indentation for pretty printing
|
||||
std::cout << std::setw(4) << j << std::endl;
|
||||
```
|
||||
|
||||
These operators work for any subclasses of `std::istream` or `std::ostream`.
|
||||
|
||||
Please note that setting the exception bit for `failbit` is inappropriate for this use case. It will result in program termination due to the `noexcept` specifier in use.
|
||||
|
||||
|
||||
### STL-like access
|
||||
|
||||
We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirement.
|
||||
|
||||
```cpp
|
||||
// create an array using push_back
|
||||
json j;
|
||||
j.push_back("foo");
|
||||
j.push_back(1);
|
||||
j.push_back(true);
|
||||
|
||||
// iterate the array
|
||||
for (json::iterator it = j.begin(); it != j.end(); ++it) {
|
||||
std::cout << *it << '\n';
|
||||
}
|
||||
|
||||
// range-based for
|
||||
for (auto& element : j) {
|
||||
std::cout << element << '\n';
|
||||
}
|
||||
|
||||
// getter/setter
|
||||
const std::string tmp = j[0];
|
||||
j[1] = 42;
|
||||
bool foo = j.at(2);
|
||||
|
||||
// other stuff
|
||||
j.size(); // 3 entries
|
||||
j.empty(); // false
|
||||
j.type(); // json::value_t::array
|
||||
j.clear(); // the array is empty again
|
||||
|
||||
// convenience type checkers
|
||||
j.is_null();
|
||||
j.is_boolean();
|
||||
j.is_number();
|
||||
j.is_object();
|
||||
j.is_array();
|
||||
j.is_string();
|
||||
|
||||
// comparison
|
||||
j == "[\"foo\", 1, true]"_json; // true
|
||||
|
||||
// create an object
|
||||
json o;
|
||||
o["foo"] = 23;
|
||||
o["bar"] = false;
|
||||
o["baz"] = 3.141;
|
||||
|
||||
// special iterator member functions for objects
|
||||
for (json::iterator it = o.begin(); it != o.end(); ++it) {
|
||||
std::cout << it.key() << " : " << it.value() << "\n";
|
||||
}
|
||||
|
||||
// find an entry
|
||||
if (o.find("foo") != o.end()) {
|
||||
// there is an entry with key "foo"
|
||||
}
|
||||
|
||||
// or simpler using count()
|
||||
int foo_present = o.count("foo"); // 1
|
||||
int fob_present = o.count("fob"); // 0
|
||||
|
||||
// delete an entry
|
||||
o.erase("foo");
|
||||
```
|
||||
|
||||
|
||||
### Conversion from STL containers
|
||||
|
||||
Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON types (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends how the elements are ordered in the respective STL container.
|
||||
|
||||
```cpp
|
||||
std::vector<int> c_vector {1, 2, 3, 4};
|
||||
json j_vec(c_vector);
|
||||
// [1, 2, 3, 4]
|
||||
|
||||
std::deque<double> c_deque {1.2, 2.3, 3.4, 5.6};
|
||||
json j_deque(c_deque);
|
||||
// [1.2, 2.3, 3.4, 5.6]
|
||||
|
||||
std::list<bool> c_list {true, true, false, true};
|
||||
json j_list(c_list);
|
||||
// [true, true, false, true]
|
||||
|
||||
std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
|
||||
json j_flist(c_flist);
|
||||
// [12345678909876, 23456789098765, 34567890987654, 45678909876543]
|
||||
|
||||
std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
|
||||
json j_array(c_array);
|
||||
// [1, 2, 3, 4]
|
||||
|
||||
std::set<std::string> c_set {"one", "two", "three", "four", "one"};
|
||||
json j_set(c_set); // only one entry for "one" is used
|
||||
// ["four", "one", "three", "two"]
|
||||
|
||||
std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
|
||||
json j_uset(c_uset); // only one entry for "one" is used
|
||||
// maybe ["two", "three", "four", "one"]
|
||||
|
||||
std::multiset<std::string> c_mset {"one", "two", "one", "four"};
|
||||
json j_mset(c_mset); // both entries for "one" are used
|
||||
// maybe ["one", "two", "one", "four"]
|
||||
|
||||
std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"};
|
||||
json j_umset(c_umset); // both entries for "one" are used
|
||||
// maybe ["one", "two", "one", "four"]
|
||||
```
|
||||
|
||||
Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON types (see examples above) can be used to to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container.
|
||||
|
||||
```cpp
|
||||
std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
|
||||
json j_map(c_map);
|
||||
// {"one": 1, "three": 3, "two": 2 }
|
||||
|
||||
std::unordered_map<const char*, double> c_umap { {"one", 1.2}, {"two", 2.3}, {"three", 3.4} };
|
||||
json j_umap(c_umap);
|
||||
// {"one": 1.2, "two": 2.3, "three": 3.4}
|
||||
|
||||
std::multimap<std::string, bool> c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
|
||||
json j_mmap(c_mmap); // only one entry for key "three" is used
|
||||
// maybe {"one": true, "two": true, "three": true}
|
||||
|
||||
std::unordered_multimap<std::string, bool> c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
|
||||
json j_ummap(c_ummap); // only one entry for key "three" is used
|
||||
// maybe {"one": true, "two": true, "three": true}
|
||||
```
|
||||
|
||||
### JSON Pointer and JSON Patch
|
||||
|
||||
The library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as alternative means to address structured values. On top of this, **JSON Patch** ([RFC 6902](https://tools.ietf.org/html/rfc6902)) allows to describe differences between two JSON values - effectively allowing patch and diff operations known from Unix.
|
||||
|
||||
```cpp
|
||||
// a JSON value
|
||||
json j_original = R"({
|
||||
"baz": ["one", "two", "three"],
|
||||
"foo": "bar"
|
||||
})"_json;
|
||||
|
||||
// access members with a JSON pointer (RFC 6901)
|
||||
j_original["/baz/1"_json_pointer];
|
||||
// "two"
|
||||
|
||||
// a JSON patch (RFC 6902)
|
||||
json j_patch = R"([
|
||||
{ "op": "replace", "path": "/baz", "value": "boo" },
|
||||
{ "op": "add", "path": "/hello", "value": ["world"] },
|
||||
{ "op": "remove", "path": "/foo"}
|
||||
])"_json;
|
||||
|
||||
// apply the patch
|
||||
json j_result = j_original.patch(j_patch);
|
||||
// {
|
||||
// "baz": "boo",
|
||||
// "hello": ["world"]
|
||||
// }
|
||||
|
||||
// calculate a JSON patch from two JSON values
|
||||
json::diff(j_result, j_original);
|
||||
// [
|
||||
// { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
|
||||
// { "op": "remove","path": "/hello" },
|
||||
// { "op": "add", "path": "/foo", "value": "bar" }
|
||||
// ]
|
||||
```
|
||||
|
||||
|
||||
### Implicit conversions
|
||||
|
||||
The type of the JSON object is determined automatically by the expression to store. Likewise, the stored value is implicitly converted.
|
||||
|
||||
```cpp
|
||||
// strings
|
||||
std::string s1 = "Hello, world!";
|
||||
json js = s1;
|
||||
std::string s2 = js;
|
||||
|
||||
// Booleans
|
||||
bool b1 = true;
|
||||
json jb = b1;
|
||||
bool b2 = jb;
|
||||
|
||||
// numbers
|
||||
int i = 42;
|
||||
json jn = i;
|
||||
double f = jn;
|
||||
|
||||
// etc.
|
||||
```
|
||||
|
||||
You can also explicitly ask for the value:
|
||||
|
||||
```cpp
|
||||
std::string vs = js.get<std::string>();
|
||||
bool vb = jb.get<bool>();
|
||||
int vi = jn.get<int>();
|
||||
|
||||
// etc.
|
||||
```
|
||||
|
||||
|
||||
## Supported compilers
|
||||
|
||||
Though it's 2016 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:
|
||||
|
||||
- GCC 4.9 - 6.0 (and possibly later)
|
||||
- Clang 3.4 - 3.9 (and possibly later)
|
||||
- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)
|
||||
|
||||
I would be happy to learn about other compilers/versions.
|
||||
|
||||
Please note:
|
||||
|
||||
- GCC 4.8 does not work because of two bugs ([55817](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55817) and [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)) in the C++11 support. Note there is a [pull request](https://github.com/nlohmann/json/pull/212) to fix some of the issues.
|
||||
- Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default.
|
||||
|
||||
```
|
||||
APP_STL := c++_shared
|
||||
NDK_TOOLCHAIN_VERSION := clang3.6
|
||||
APP_CPPFLAGS += -frtti -fexceptions
|
||||
```
|
||||
|
||||
The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10.
|
||||
|
||||
- For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219).
|
||||
|
||||
The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json) and [AppVeyor](https://ci.appveyor.com/project/nlohmann/json):
|
||||
|
||||
| Compiler | Operating System | Version String |
|
||||
|-----------------|------------------------------|----------------|
|
||||
| GCC 4.9.3 | Ubuntu 14.04.4 LTS | g++-4.9 (Ubuntu 4.9.3-8ubuntu2~14.04) 4.9.3 |
|
||||
| GCC 5.3.0 | Ubuntu 14.04.4 LTS | g++-5 (Ubuntu 5.3.0-3ubuntu1~14.04) 5.3.0 20151204 |
|
||||
| GCC 6.1.1 | Ubuntu 14.04.4 LTS | g++-6 (Ubuntu 6.1.1-3ubuntu11~14.04.1) 6.1.1 20160511 |
|
||||
| Clang 3.6.0 | Ubuntu 14.04.4 LTS | clang version 3.6.0 (tags/RELEASE_360/final) |
|
||||
| Clang 3.6.1 | Ubuntu 14.04.4 LTS | clang version 3.6.1 (tags/RELEASE_361/final) |
|
||||
| Clang 3.6.2 | Ubuntu 14.04.4 LTS | clang version 3.6.2 (tags/RELEASE_362/final) |
|
||||
| Clang 3.7.0 | Ubuntu 14.04.4 LTS | clang version 3.7.0 (tags/RELEASE_370/final) |
|
||||
| Clang 3.7.1 | Ubuntu 14.04.4 LTS | clang version 3.7.1 (tags/RELEASE_371/final) |
|
||||
| Clang 3.8.0 | Ubuntu 14.04.4 LTS | clang version 3.8.0 (tags/RELEASE_380/final) |
|
||||
| Clang 3.8.1 | Ubuntu 14.04.4 LTS | clang version 3.8.1 (tags/RELEASE_381/final) |
|
||||
| Clang Xcode 6.1 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn) |
|
||||
| Clang Xcode 6.2 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn) |
|
||||
| Clang Xcode 6.3 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn) |
|
||||
| Clang Xcode 6.4 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) |
|
||||
| Clang Xcode 7.1 | Darwin Kernel Version 14.5.0 (OSX 10.10.5) | Apple LLVM version 7.0.0 (clang-700.1.76) |
|
||||
| Clang Xcode 7.2 | Darwin Kernel Version 15.0.0 (OSX 10.10.5) | Apple LLVM version 7.0.2 (clang-700.1.81) |
|
||||
| Clang Xcode 7.3 | Darwin Kernel Version 15.0.0 (OSX 10.10.5) | Apple LLVM version 7.3.0 (clang-703.0.29) |
|
||||
| Clang Xcode 8.0 | Darwin Kernel Version 15.6.0 (OSX 10.11.6) | Apple LLVM version 8.0.0 (clang-800.0.38) |
|
||||
| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25123.0 |
|
||||
|
||||
|
||||
## License
|
||||
|
||||
<img align="right" src="http://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png">
|
||||
|
||||
The class is licensed under the [MIT License](http://opensource.org/licenses/MIT):
|
||||
|
||||
Copyright © 2013-2016 [Niels Lohmann](http://nlohmann.me)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
## Thanks
|
||||
|
||||
I deeply appreciate the help of the following people.
|
||||
|
||||
- [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization.
|
||||
- [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes.
|
||||
- [kirkshoop](https://github.com/kirkshoop) made the iterators of the class composable to other libraries.
|
||||
- [wancw](https://github.com/wanwc) fixed a bug that hindered the class to compile with Clang.
|
||||
- Tomas Åblad found a bug in the iterator implementation.
|
||||
- [Joshua C. Randall](https://github.com/jrandall) fixed a bug in the floating-point serialization.
|
||||
- [Aaron Burghardt](https://github.com/aburgh) implemented code to parse streams incrementally. Furthermore, he greatly improved the parser class by allowing the definition of a filter function to discard undesired elements while parsing.
|
||||
- [Daniel Kopeček](https://github.com/dkopecek) fixed a bug in the compilation with GCC 5.0.
|
||||
- [Florian Weber](https://github.com/Florianjw) fixed a bug in and improved the performance of the comparison operators.
|
||||
- [Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping.
|
||||
- [易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums.
|
||||
- [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio.
|
||||
- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements.
|
||||
- [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling.
|
||||
- [dariomt](https://github.com/dariomt) fixed some typos in the examples.
|
||||
- [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation.
|
||||
- [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue.
|
||||
- [Huu Nguyen](https://github.com/whoshuu) correct a variable name in the documentation.
|
||||
- [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference.
|
||||
- [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values.
|
||||
- [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK.
|
||||
- [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio.
|
||||
- [406345](https://github.com/406345) fixed two small warnings.
|
||||
- [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function.
|
||||
- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines.
|
||||
- [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers.
|
||||
- [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file.
|
||||
- [msm-](https://github.com/msm-) added support for american fuzzy lop.
|
||||
- [Annihil](https://github.com/Annihil) fixed an example in the README file.
|
||||
- [Themercee](https://github.com/Themercee) noted a wrong URL in the README file.
|
||||
- [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`.
|
||||
- [abc100m](https://github.com/abc100m) analyzed the issues with GCC 4.8 and proposed a [partial solution](https://github.com/nlohmann/json/pull/212).
|
||||
- [zewt](https://github.com/zewt) added useful notes to the README file about Android.
|
||||
- [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake.
|
||||
- [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files.
|
||||
- [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal).
|
||||
- [Mário Feroldi](https://github.com/thelostt) fixed a small typo.
|
||||
- [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release.
|
||||
- [Damien](https://github.com/dtoma) fixed one of the last conversion warnings.
|
||||
- [Thomas Braun](https://github.com/t-b) fixed a warning in a test case.
|
||||
- [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290).
|
||||
- [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation.
|
||||
- [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`.
|
||||
- [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion.
|
||||
- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable.
|
||||
- [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file.
|
||||
|
||||
Thanks a lot for helping out!
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](http://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a2e26bd0b0168abb61f67ad5bcd5b9fa1.html#a2e26bd0b0168abb61f67ad5bcd5b9fa1) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a674de1ee73e6bf4843fc5dc1351fb726.html#a674de1ee73e6bf4843fc5dc1351fb726).
|
||||
- As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions.
|
||||
- The library supports **Unicode input** as follows:
|
||||
- Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 7159](http://rfc7159.net/rfc7159#rfc.section.8.1).
|
||||
- Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse errors.
|
||||
- [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library.
|
||||
- Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors.
|
||||
|
||||
|
||||
## Execute unit tests
|
||||
|
||||
To compile and run the tests, you need to execute
|
||||
|
||||
```sh
|
||||
$ make check
|
||||
|
||||
===============================================================================
|
||||
All tests passed (8905491 assertions in 36 test cases)
|
||||
```
|
||||
|
||||
Alternatively, you can use [CMake](https://cmake.org) and run
|
||||
|
||||
```sh
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake ..
|
||||
$ make
|
||||
$ ctest
|
||||
```
|
||||
|
||||
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).
|
||||
12275
zerotierone/ext/json/json.hpp
Normal file
12275
zerotierone/ext/json/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
91
zerotierone/java/CMakeLists.txt
Normal file
91
zerotierone/java/CMakeLists.txt
Normal file
@@ -0,0 +1,91 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
project(ZeroTierOneJNI)
|
||||
|
||||
find_package(Java COMPONENTS Development)
|
||||
message("JAVA_HOME: $ENV{JAVA_HOME}")
|
||||
|
||||
if(WIN32)
|
||||
set(Java_INCLUDE_DIRS $ENV{JAVA_HOME}/include)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(Java_INCLUDE_DIRS "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/System/Library/Frameworks/JavaVM.framework/Headers")
|
||||
endif()
|
||||
|
||||
message("Java Include Dirs: ${Java_INCLUDE_DIRS}")
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(-DNOMINMAX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /W3 /MP")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -arch i386 -arch x86_64 -Wall -O3 -flto -fPIE -fvectorize -fstack-protector -mmacosx-version-min=10.7 -Wno-unused-private-field")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} -fno-rtti")
|
||||
endif()
|
||||
|
||||
set(src_files
|
||||
../ext/lz4/lz4.c
|
||||
../ext/json-parser/json.c
|
||||
../ext/http-parser/http_parser.c
|
||||
../node/C25519.cpp
|
||||
../node/CertificateOfMembership.cpp
|
||||
../node/Defaults.cpp
|
||||
../node/Dictionary.cpp
|
||||
../node/Identity.cpp
|
||||
../node/IncomingPacket.cpp
|
||||
../node/InetAddress.cpp
|
||||
../node/Multicaster.cpp
|
||||
../node/Network.cpp
|
||||
../node/NetworkConfig.cpp
|
||||
../node/Node.cpp
|
||||
../node/OutboundMulticast.cpp
|
||||
../node/Packet.cpp
|
||||
../node/Peer.cpp
|
||||
../node/Poly1305.cpp
|
||||
../node/Salsa20.cpp
|
||||
../node/SelfAwareness.cpp
|
||||
../node/SHA512.cpp
|
||||
../node/Switch.cpp
|
||||
../node/Topology.cpp
|
||||
../node/Utils.cpp
|
||||
../osdep/Http.cpp
|
||||
../osdep/OSUtils.cpp
|
||||
jni/com_zerotierone_sdk_Node.cpp
|
||||
jni/ZT_jniutils.cpp
|
||||
jni/ZT_jnicache.cpp
|
||||
)
|
||||
|
||||
set(include_dirs
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../node/
|
||||
${Java_INCLUDE_DIRS})
|
||||
|
||||
if(WIN32)
|
||||
set(include_dirs
|
||||
${include_dirs}
|
||||
${Java_INCLUDE_DIRS}/win32)
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${include_dirs}
|
||||
)
|
||||
|
||||
add_library(${PROJECT_NAME} SHARED ${src_files})
|
||||
|
||||
if(APPLE)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".jnilib")
|
||||
endif()
|
||||
|
||||
set(link_libs )
|
||||
|
||||
if(WIN32)
|
||||
set(link_libs
|
||||
wsock32
|
||||
ws2_32
|
||||
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} ${link_libs})
|
||||
17
zerotierone/java/README.md
Normal file
17
zerotierone/java/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
ZeroTier One SDK - Android JNI Wrapper
|
||||
=====
|
||||
|
||||
|
||||
Building
|
||||
-----
|
||||
|
||||
Reqires:
|
||||
|
||||
* JDK
|
||||
* ANT
|
||||
* Android NDK
|
||||
|
||||
Required Environment Variables:
|
||||
|
||||
* NDK\_BUILD\_LOC - Path do the ndk-build script in the Android NDK
|
||||
* ANDROID\_PLATFORM - path to the directory android.jar lives (on Windows: C:\Users\<username>\AppData\Local\Android\sdk\platforms\android-21)
|
||||
118
zerotierone/java/build.xml
Normal file
118
zerotierone/java/build.xml
Normal file
@@ -0,0 +1,118 @@
|
||||
<project default="build_jar" name="ZeroTierOneSDK" basedir=".">
|
||||
<property environment="env"/>
|
||||
|
||||
<condition property="isWindows">
|
||||
<os family="windows"/>
|
||||
</condition>
|
||||
|
||||
<condition property="isMac">
|
||||
<os family="mac"/>
|
||||
</condition>
|
||||
|
||||
<target name="clean_ant">
|
||||
<delete dir="bin" failonerror="false"/>
|
||||
<delete dir="classes" failonerror="false"/>
|
||||
<delete dir="build_win32" failonerror="false"/>
|
||||
<delete dir="build_win64" failonerror="false"/>
|
||||
<delete dir="mac32_64" failonerror="false"/>
|
||||
<delete dir="libs" failonerror="false"/>
|
||||
<delete dir="obj" failonerror="false"/>
|
||||
</target>
|
||||
|
||||
<target name="build_java">
|
||||
<echo message="os.name = ${os.name}"/>
|
||||
<echo message="os.arch = ${os.arch}"/>
|
||||
<echo message="ant.java.version = ${ant.java.version}"/>
|
||||
<echo message="java.version = ${java.version}"/>
|
||||
<echo message="ndk.loc = ${env.NDK_BUILD_LOC}"/>
|
||||
<echo message="sdk.loc = ${env.ANDROID_PLATFORM}"/>
|
||||
<echo message="user.dir = ${user.dir}"/>
|
||||
<echo message="zt1.dir = ${env.ZT}"/>
|
||||
<mkdir dir="bin"/>
|
||||
<mkdir dir="classes"/>
|
||||
<javac srcdir="src"
|
||||
destdir="classes"
|
||||
source="1.7"
|
||||
target="1.7"
|
||||
classpath="${env.ANDROID_PLATFORM}/android.jar"
|
||||
includeantruntime="false"/>
|
||||
</target>
|
||||
|
||||
<target name="build_android">
|
||||
<exec dir="jni" executable="${env.NDK_BUILD_LOC}" failonerror="true">
|
||||
<arg value="ZT1=${env.ZT}"/>
|
||||
<arg value="V=1"/>
|
||||
<!-- <arg value="NDK_DEBUG=1"/> -->
|
||||
</exec>
|
||||
<copy file="libs/arm64-v8a/libZeroTierOneJNI.so"
|
||||
tofile="classes/lib/arm64-v8a/libZeroTierOneJNI.so"
|
||||
overwrite="true"/>
|
||||
<copy file="libs/armeabi/libZeroTierOneJNI.so"
|
||||
tofile="classes/lib/armeabi/libZeroTierOneJNI.so"
|
||||
overwrite="true"/>
|
||||
<copy file="libs/armeabi-v7a/libZeroTierOneJNI.so"
|
||||
tofile="classes/lib/armeabi-v7a/libZeroTierOneJNI.so"
|
||||
overwrite="true"/>
|
||||
<copy file="libs/mips/libZeroTierOneJNI.so"
|
||||
tofile="classes/lib/mips/libZeroTierOneJNI.so"
|
||||
overwrite="true"/>
|
||||
<copy file="libs/mips64/libZeroTierOneJNI.so"
|
||||
tofile="classes/lib/mips64/libZeroTierOne.so"
|
||||
overwrite="true"/>
|
||||
<copy file="libs/x86/libZeroTierOneJNI.so"
|
||||
tofile="classes/lib/x86/libZeroTierOneJNI.so"
|
||||
overwrite="true"/>
|
||||
<copy file="libs/x86_64/libZeroTierOneJNI.so"
|
||||
tofile="classes/lib/x86_64/libZeroTierOneJNI.so"
|
||||
overwrite="true"/>
|
||||
</target>
|
||||
|
||||
|
||||
<target name="windows" if="isWindows">
|
||||
<mkdir dir="build_win32"/>
|
||||
<exec dir="build_win32/" executable="cmake" failonerror="true">
|
||||
<arg line=".. -G"Visual Studio 11 2012" -DCMAKE_BUILD_TYPE=Release"/>
|
||||
</exec>
|
||||
<exec dir="build_win32/" executable="cmake" failonerror="true">
|
||||
<arg line="--build . --config Release"/>
|
||||
</exec>
|
||||
<copy file="build_win32/Release/ZeroTierOneJNI.dll"
|
||||
tofile="classes/lib/ZeroTierOneJNI_win32.dll"
|
||||
overwrite="true"/>
|
||||
|
||||
<mkdir dir="build_win64"/>
|
||||
<exec dir="build_win64/" executable="cmake" failonerror="true">
|
||||
<arg line=".. -G"Visual Studio 11 2012 Win64" -DCMAKE_BUILD_TYPE=Release"/>
|
||||
</exec>
|
||||
<exec dir="build_win64/" executable="cmake" failonerror="true">
|
||||
<arg line="--build . --config Release"/>
|
||||
</exec>
|
||||
<copy file="build_win64/Release/ZeroTierOneJNI.dll"
|
||||
tofile="classes/lib/ZeroTierOneJNI_win64.dll"
|
||||
overwrite="true"/>
|
||||
</target>
|
||||
|
||||
<target name="mac" if="isMac">
|
||||
<mkdir dir="mac32_64"/>
|
||||
<exec dir="mac32_64/" executable="cmake" failonerror="true">
|
||||
<arg line=".. -DCMAKE_BUILD_TYPE=Release"/>
|
||||
</exec>
|
||||
<exec dir="mac32_64/" executable="cmake" failonerror="true">
|
||||
<arg line="--build . --config Release"/>
|
||||
</exec>
|
||||
<copy file="mac32_64/libZeroTierOneJNI.jnilib"
|
||||
tofile="classes/lib/libZeroTierOneJNI.jnilib"
|
||||
overwrite="true"/>
|
||||
</target>
|
||||
|
||||
<target name="build_jar" depends="build_java,build_android,windows,mac">
|
||||
<jar destfile="bin/ZeroTierOneSDK.jar" basedir="classes"/>
|
||||
</target>
|
||||
|
||||
<target name="docs">
|
||||
<echo message="Generating Javadocs"/>
|
||||
<mkdir dir="doc/"/>
|
||||
<javadoc sourcepath="src/"
|
||||
destdir="doc/"/>
|
||||
</target>
|
||||
</project>
|
||||
46
zerotierone/java/jni/Android.mk
Normal file
46
zerotierone/java/jni/Android.mk
Normal file
@@ -0,0 +1,46 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := ZeroTierOneJNI
|
||||
LOCAL_C_INCLUDES := $(ZT1)/include
|
||||
LOCAL_C_INCLUDES += $(ZT1)/node
|
||||
LOCAL_LDLIBS := -llog -latomic
|
||||
# LOCAL_CFLAGS := -g
|
||||
|
||||
# ZeroTierOne SDK source files
|
||||
LOCAL_SRC_FILES := \
|
||||
$(ZT1)/node/C25519.cpp \
|
||||
$(ZT1)/node/Capability.cpp \
|
||||
$(ZT1)/node/CertificateOfMembership.cpp \
|
||||
$(ZT1)/node/CertificateOfOwnership.cpp \
|
||||
$(ZT1)/node/Identity.cpp \
|
||||
$(ZT1)/node/IncomingPacket.cpp \
|
||||
$(ZT1)/node/InetAddress.cpp \
|
||||
$(ZT1)/node/Membership.cpp \
|
||||
$(ZT1)/node/Multicaster.cpp \
|
||||
$(ZT1)/node/Network.cpp \
|
||||
$(ZT1)/node/NetworkConfig.cpp \
|
||||
$(ZT1)/node/Node.cpp \
|
||||
$(ZT1)/node/OutboundMulticast.cpp \
|
||||
$(ZT1)/node/Packet.cpp \
|
||||
$(ZT1)/node/Path.cpp \
|
||||
$(ZT1)/node/Peer.cpp \
|
||||
$(ZT1)/node/Poly1305.cpp \
|
||||
$(ZT1)/node/Revocation.cpp \
|
||||
$(ZT1)/node/Salsa20.cpp \
|
||||
$(ZT1)/node/SelfAwareness.cpp \
|
||||
$(ZT1)/node/SHA512.cpp \
|
||||
$(ZT1)/node/Switch.cpp \
|
||||
$(ZT1)/node/Tag.cpp \
|
||||
$(ZT1)/node/Topology.cpp \
|
||||
$(ZT1)/node/Utils.cpp
|
||||
|
||||
|
||||
# JNI Files
|
||||
LOCAL_SRC_FILES += \
|
||||
com_zerotierone_sdk_Node.cpp \
|
||||
ZT_jniutils.cpp \
|
||||
ZT_jnilookup.cpp
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
5
zerotierone/java/jni/Application.mk
Normal file
5
zerotierone/java/jni/Application.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
# NDK_TOOLCHAIN_VERSION := clang3.5
|
||||
APP_STL := gnustl_static
|
||||
APP_CPPFLAGS := -O3 -fPIC -fPIE -Wall -fstack-protector -fexceptions -fno-strict-aliasing -Wno-deprecated-register -DZT_NO_TYPE_PUNNING=1
|
||||
APP_PLATFORM := android-14
|
||||
APP_ABI := all
|
||||
158
zerotierone/java/jni/ZT_jnilookup.cpp
Normal file
158
zerotierone/java/jni/ZT_jnilookup.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#include "ZT_jnilookup.h"
|
||||
#include "ZT_jniutils.h"
|
||||
|
||||
JniLookup::JniLookup()
|
||||
: m_jvm(NULL)
|
||||
{
|
||||
LOGV("JNI Cache Created");
|
||||
}
|
||||
|
||||
JniLookup::JniLookup(JavaVM *jvm)
|
||||
: m_jvm(jvm)
|
||||
{
|
||||
LOGV("JNI Cache Created");
|
||||
}
|
||||
|
||||
JniLookup::~JniLookup()
|
||||
{
|
||||
LOGV("JNI Cache Destroyed");
|
||||
}
|
||||
|
||||
|
||||
void JniLookup::setJavaVM(JavaVM *jvm)
|
||||
{
|
||||
LOGV("Assigned JVM to object");
|
||||
m_jvm = jvm;
|
||||
}
|
||||
|
||||
|
||||
jclass JniLookup::findClass(const std::string &name)
|
||||
{
|
||||
if(!m_jvm)
|
||||
return NULL;
|
||||
|
||||
// get the class from the JVM
|
||||
JNIEnv *env = NULL;
|
||||
if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
|
||||
{
|
||||
LOGE("Error retreiving JNI Environment");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jclass cls = env->FindClass(name.c_str());
|
||||
if(env->ExceptionCheck())
|
||||
{
|
||||
LOGE("Error finding class: %s", name.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cls;
|
||||
}
|
||||
|
||||
|
||||
jmethodID JniLookup::findMethod(jclass cls, const std::string &methodName, const std::string &methodSig)
|
||||
{
|
||||
if(!m_jvm)
|
||||
return NULL;
|
||||
|
||||
JNIEnv *env = NULL;
|
||||
if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jmethodID mid = env->GetMethodID(cls, methodName.c_str(), methodSig.c_str());
|
||||
if(env->ExceptionCheck())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mid;
|
||||
}
|
||||
|
||||
jmethodID JniLookup::findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig)
|
||||
{
|
||||
if(!m_jvm)
|
||||
return NULL;
|
||||
|
||||
JNIEnv *env = NULL;
|
||||
if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jmethodID mid = env->GetStaticMethodID(cls, methodName.c_str(), methodSig.c_str());
|
||||
if(env->ExceptionCheck())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mid;
|
||||
}
|
||||
|
||||
jfieldID JniLookup::findField(jclass cls, const std::string &fieldName, const std::string &typeStr)
|
||||
{
|
||||
if(!m_jvm)
|
||||
return NULL;
|
||||
|
||||
JNIEnv *env = NULL;
|
||||
if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jfieldID fid = env->GetFieldID(cls, fieldName.c_str(), typeStr.c_str());
|
||||
if(env->ExceptionCheck())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fid;
|
||||
}
|
||||
|
||||
jfieldID JniLookup::findStaticField(jclass cls, const std::string &fieldName, const std::string &typeStr)
|
||||
{
|
||||
if(!m_jvm)
|
||||
return NULL;
|
||||
|
||||
JNIEnv *env = NULL;
|
||||
if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jfieldID fid = env->GetStaticFieldID(cls, fieldName.c_str(), typeStr.c_str());
|
||||
if(env->ExceptionCheck())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fid;
|
||||
}
|
||||
54
zerotierone/java/jni/ZT_jnilookup.h
Normal file
54
zerotierone/java/jni/ZT_jnilookup.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef ZT_JNILOOKUP_H_
|
||||
#define ZT_JNILOOKUP_H_
|
||||
|
||||
#include <jni.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
class JniLookup {
|
||||
public:
|
||||
JniLookup();
|
||||
JniLookup(JavaVM *jvm);
|
||||
~JniLookup();
|
||||
|
||||
void setJavaVM(JavaVM *jvm);
|
||||
|
||||
jclass findClass(const std::string &name);
|
||||
jmethodID findMethod(jclass cls, const std::string &methodName, const std::string &methodSig);
|
||||
jmethodID findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig);
|
||||
jfieldID findField(jclass cls, const std::string &fieldName, const std::string &typeStr);
|
||||
jfieldID findStaticField(jclass cls, const std::string &fieldName, const std::string &typeStr);
|
||||
private:
|
||||
JavaVM *m_jvm;
|
||||
};
|
||||
|
||||
#endif
|
||||
941
zerotierone/java/jni/ZT_jniutils.cpp
Normal file
941
zerotierone/java/jni/ZT_jniutils.cpp
Normal file
@@ -0,0 +1,941 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ZT_jniutils.h"
|
||||
#include "ZT_jnilookup.h"
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
|
||||
extern JniLookup lookup;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
jobject createResultObject(JNIEnv *env, ZT_ResultCode code)
|
||||
{
|
||||
jclass resultClass = NULL;
|
||||
|
||||
jobject resultObject = NULL;
|
||||
|
||||
resultClass = lookup.findClass("com/zerotier/sdk/ResultCode");
|
||||
if(resultClass == NULL)
|
||||
{
|
||||
LOGE("Couldnt find ResultCode class");
|
||||
return NULL; // exception thrown
|
||||
}
|
||||
|
||||
std::string fieldName;
|
||||
switch(code)
|
||||
{
|
||||
case ZT_RESULT_OK:
|
||||
LOGV("ZT_RESULT_OK");
|
||||
fieldName = "RESULT_OK";
|
||||
break;
|
||||
case ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY:
|
||||
LOGV("ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY");
|
||||
fieldName = "RESULT_FATAL_ERROR_OUT_OF_MEMORY";
|
||||
break;
|
||||
case ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED:
|
||||
LOGV("RESULT_FATAL_ERROR_DATA_STORE_FAILED");
|
||||
fieldName = "RESULT_FATAL_ERROR_DATA_STORE_FAILED";
|
||||
break;
|
||||
case ZT_RESULT_ERROR_NETWORK_NOT_FOUND:
|
||||
LOGV("RESULT_FATAL_ERROR_DATA_STORE_FAILED");
|
||||
fieldName = "RESULT_ERROR_NETWORK_NOT_FOUND";
|
||||
break;
|
||||
case ZT_RESULT_FATAL_ERROR_INTERNAL:
|
||||
default:
|
||||
LOGV("RESULT_FATAL_ERROR_DATA_STORE_FAILED");
|
||||
fieldName = "RESULT_FATAL_ERROR_INTERNAL";
|
||||
break;
|
||||
}
|
||||
|
||||
jfieldID enumField = lookup.findStaticField(resultClass, fieldName.c_str(), "Lcom/zerotier/sdk/ResultCode;");
|
||||
if(env->ExceptionCheck() || enumField == NULL)
|
||||
{
|
||||
LOGE("Error on FindStaticField");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
resultObject = env->GetStaticObjectField(resultClass, enumField);
|
||||
if(env->ExceptionCheck() || resultObject == NULL)
|
||||
{
|
||||
LOGE("Error on GetStaticObjectField");
|
||||
}
|
||||
return resultObject;
|
||||
}
|
||||
|
||||
|
||||
jobject createVirtualNetworkStatus(JNIEnv *env, ZT_VirtualNetworkStatus status)
|
||||
{
|
||||
jobject statusObject = NULL;
|
||||
|
||||
jclass statusClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkStatus");
|
||||
if(statusClass == NULL)
|
||||
{
|
||||
return NULL; // exception thrown
|
||||
}
|
||||
|
||||
std::string fieldName;
|
||||
switch(status)
|
||||
{
|
||||
case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION:
|
||||
fieldName = "NETWORK_STATUS_REQUESTING_CONFIGURATION";
|
||||
break;
|
||||
case ZT_NETWORK_STATUS_OK:
|
||||
fieldName = "NETWORK_STATUS_OK";
|
||||
break;
|
||||
case ZT_NETWORK_STATUS_ACCESS_DENIED:
|
||||
fieldName = "NETWORK_STATUS_ACCESS_DENIED";
|
||||
break;
|
||||
case ZT_NETWORK_STATUS_NOT_FOUND:
|
||||
fieldName = "NETWORK_STATUS_NOT_FOUND";
|
||||
break;
|
||||
case ZT_NETWORK_STATUS_PORT_ERROR:
|
||||
fieldName = "NETWORK_STATUS_PORT_ERROR";
|
||||
break;
|
||||
case ZT_NETWORK_STATUS_CLIENT_TOO_OLD:
|
||||
fieldName = "NETWORK_STATUS_CLIENT_TOO_OLD";
|
||||
break;
|
||||
}
|
||||
|
||||
jfieldID enumField = lookup.findStaticField(statusClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkStatus;");
|
||||
|
||||
statusObject = env->GetStaticObjectField(statusClass, enumField);
|
||||
|
||||
return statusObject;
|
||||
}
|
||||
|
||||
jobject createEvent(JNIEnv *env, ZT_Event event)
|
||||
{
|
||||
jclass eventClass = NULL;
|
||||
jobject eventObject = NULL;
|
||||
|
||||
eventClass = lookup.findClass("com/zerotier/sdk/Event");
|
||||
if(eventClass == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string fieldName;
|
||||
switch(event)
|
||||
{
|
||||
case ZT_EVENT_UP:
|
||||
fieldName = "EVENT_UP";
|
||||
break;
|
||||
case ZT_EVENT_OFFLINE:
|
||||
fieldName = "EVENT_OFFLINE";
|
||||
break;
|
||||
case ZT_EVENT_ONLINE:
|
||||
fieldName = "EVENT_ONLINE";
|
||||
break;
|
||||
case ZT_EVENT_DOWN:
|
||||
fieldName = "EVENT_DOWN";
|
||||
break;
|
||||
case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION:
|
||||
fieldName = "EVENT_FATAL_ERROR_IDENTITY_COLLISION";
|
||||
break;
|
||||
case ZT_EVENT_TRACE:
|
||||
fieldName = "EVENT_TRACE";
|
||||
break;
|
||||
case ZT_EVENT_USER_MESSAGE:
|
||||
break;
|
||||
}
|
||||
|
||||
jfieldID enumField = lookup.findStaticField(eventClass, fieldName.c_str(), "Lcom/zerotier/sdk/Event;");
|
||||
|
||||
eventObject = env->GetStaticObjectField(eventClass, enumField);
|
||||
|
||||
return eventObject;
|
||||
}
|
||||
|
||||
jobject createPeerRole(JNIEnv *env, ZT_PeerRole role)
|
||||
{
|
||||
jclass peerRoleClass = NULL;
|
||||
jobject peerRoleObject = NULL;
|
||||
|
||||
peerRoleClass = lookup.findClass("com/zerotier/sdk/PeerRole");
|
||||
if(peerRoleClass == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string fieldName;
|
||||
switch(role)
|
||||
{
|
||||
case ZT_PEER_ROLE_LEAF:
|
||||
fieldName = "PEER_ROLE_LEAF";
|
||||
break;
|
||||
case ZT_PEER_ROLE_MOON:
|
||||
fieldName = "PEER_ROLE_MOON";
|
||||
break;
|
||||
case ZT_PEER_ROLE_PLANET:
|
||||
fieldName = "PEER_ROLE_PLANET";
|
||||
break;
|
||||
}
|
||||
|
||||
jfieldID enumField = lookup.findStaticField(peerRoleClass, fieldName.c_str(), "Lcom/zerotier/sdk/PeerRole;");
|
||||
|
||||
peerRoleObject = env->GetStaticObjectField(peerRoleClass, enumField);
|
||||
|
||||
return peerRoleObject;
|
||||
}
|
||||
|
||||
jobject createVirtualNetworkType(JNIEnv *env, ZT_VirtualNetworkType type)
|
||||
{
|
||||
jclass vntypeClass = NULL;
|
||||
jobject vntypeObject = NULL;
|
||||
|
||||
vntypeClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkType");
|
||||
if(env->ExceptionCheck() || vntypeClass == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string fieldName;
|
||||
switch(type)
|
||||
{
|
||||
case ZT_NETWORK_TYPE_PRIVATE:
|
||||
fieldName = "NETWORK_TYPE_PRIVATE";
|
||||
break;
|
||||
case ZT_NETWORK_TYPE_PUBLIC:
|
||||
fieldName = "NETWORK_TYPE_PUBLIC";
|
||||
break;
|
||||
}
|
||||
|
||||
jfieldID enumField = lookup.findStaticField(vntypeClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkType;");
|
||||
vntypeObject = env->GetStaticObjectField(vntypeClass, enumField);
|
||||
return vntypeObject;
|
||||
}
|
||||
|
||||
jobject createVirtualNetworkConfigOperation(JNIEnv *env, ZT_VirtualNetworkConfigOperation op)
|
||||
{
|
||||
jclass vnetConfigOpClass = NULL;
|
||||
jobject vnetConfigOpObject = NULL;
|
||||
|
||||
vnetConfigOpClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkConfigOperation");
|
||||
if(env->ExceptionCheck() || vnetConfigOpClass == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string fieldName;
|
||||
switch(op)
|
||||
{
|
||||
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP:
|
||||
fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_UP";
|
||||
break;
|
||||
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE:
|
||||
fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE";
|
||||
break;
|
||||
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN:
|
||||
fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN";
|
||||
break;
|
||||
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY:
|
||||
fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY";
|
||||
break;
|
||||
}
|
||||
|
||||
jfieldID enumField = lookup.findStaticField(vnetConfigOpClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkConfigOperation;");
|
||||
vnetConfigOpObject = env->GetStaticObjectField(vnetConfigOpClass, enumField);
|
||||
return vnetConfigOpObject;
|
||||
}
|
||||
|
||||
jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr)
|
||||
{
|
||||
LOGV("newInetAddress");
|
||||
jclass inetAddressClass = NULL;
|
||||
jmethodID inetAddress_getByAddress = NULL;
|
||||
|
||||
inetAddressClass = lookup.findClass("java/net/InetAddress");
|
||||
if(env->ExceptionCheck() || inetAddressClass == NULL)
|
||||
{
|
||||
LOGE("Error finding InetAddress class");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inetAddress_getByAddress = lookup.findStaticMethod(
|
||||
inetAddressClass, "getByAddress", "([B)Ljava/net/InetAddress;");
|
||||
if(env->ExceptionCheck() || inetAddress_getByAddress == NULL)
|
||||
{
|
||||
LOGE("Erorr finding getByAddress() static method");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobject inetAddressObj = NULL;
|
||||
switch(addr.ss_family)
|
||||
{
|
||||
case AF_INET6:
|
||||
{
|
||||
sockaddr_in6 *ipv6 = (sockaddr_in6*)&addr;
|
||||
jbyteArray buff = env->NewByteArray(16);
|
||||
if(buff == NULL)
|
||||
{
|
||||
LOGE("Error creating IPV6 byte array");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
env->SetByteArrayRegion(buff, 0, 16, (jbyte*)ipv6->sin6_addr.s6_addr);
|
||||
inetAddressObj = env->CallStaticObjectMethod(
|
||||
inetAddressClass, inetAddress_getByAddress, buff);
|
||||
}
|
||||
break;
|
||||
case AF_INET:
|
||||
{
|
||||
sockaddr_in *ipv4 = (sockaddr_in*)&addr;
|
||||
jbyteArray buff = env->NewByteArray(4);
|
||||
if(buff == NULL)
|
||||
{
|
||||
LOGE("Error creating IPV4 byte array");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
env->SetByteArrayRegion(buff, 0, 4, (jbyte*)&ipv4->sin_addr);
|
||||
inetAddressObj = env->CallStaticObjectMethod(
|
||||
inetAddressClass, inetAddress_getByAddress, buff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(env->ExceptionCheck() || inetAddressObj == NULL) {
|
||||
LOGE("Error creating InetAddress object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return inetAddressObj;
|
||||
}
|
||||
|
||||
jobject newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr)
|
||||
{
|
||||
LOGV("newInetSocketAddress Called");
|
||||
jclass inetSocketAddressClass = NULL;
|
||||
jmethodID inetSocketAddress_constructor = NULL;
|
||||
|
||||
inetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress");
|
||||
if(env->ExceptionCheck() || inetSocketAddressClass == NULL)
|
||||
{
|
||||
LOGE("Error finding InetSocketAddress Class");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobject inetAddressObject = NULL;
|
||||
|
||||
if(addr.ss_family != 0)
|
||||
{
|
||||
inetAddressObject = newInetAddress(env, addr);
|
||||
|
||||
if(env->ExceptionCheck() || inetAddressObject == NULL)
|
||||
{
|
||||
LOGE("Error creating new inet address");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inetSocketAddress_constructor = lookup.findMethod(
|
||||
inetSocketAddressClass, "<init>", "(Ljava/net/InetAddress;I)V");
|
||||
if(env->ExceptionCheck() || inetSocketAddress_constructor == NULL)
|
||||
{
|
||||
LOGE("Error finding InetSocketAddress constructor");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int port = 0;
|
||||
switch(addr.ss_family)
|
||||
{
|
||||
case AF_INET6:
|
||||
{
|
||||
LOGV("IPV6 Address");
|
||||
sockaddr_in6 *ipv6 = (sockaddr_in6*)&addr;
|
||||
port = ntohs(ipv6->sin6_port);
|
||||
LOGV("Port %d", port);
|
||||
}
|
||||
break;
|
||||
case AF_INET:
|
||||
{
|
||||
LOGV("IPV4 Address");
|
||||
sockaddr_in *ipv4 = (sockaddr_in*)&addr;
|
||||
port = ntohs(ipv4->sin_port);
|
||||
LOGV("Port: %d", port);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
jobject inetSocketAddressObject = env->NewObject(inetSocketAddressClass, inetSocketAddress_constructor, inetAddressObject, port);
|
||||
if(env->ExceptionCheck() || inetSocketAddressObject == NULL) {
|
||||
LOGE("Error creating InetSocketAddress object");
|
||||
}
|
||||
return inetSocketAddressObject;
|
||||
}
|
||||
|
||||
jobject newPeerPhysicalPath(JNIEnv *env, const ZT_PeerPhysicalPath &ppp)
|
||||
{
|
||||
LOGV("newPeerPhysicalPath Called");
|
||||
jclass pppClass = NULL;
|
||||
|
||||
jfieldID addressField = NULL;
|
||||
jfieldID lastSendField = NULL;
|
||||
jfieldID lastReceiveField = NULL;
|
||||
jfieldID preferredField = NULL;
|
||||
|
||||
jmethodID ppp_constructor = NULL;
|
||||
|
||||
pppClass = lookup.findClass("com/zerotier/sdk/PeerPhysicalPath");
|
||||
if(env->ExceptionCheck() || pppClass == NULL)
|
||||
{
|
||||
LOGE("Error finding PeerPhysicalPath class");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addressField = lookup.findField(pppClass, "address", "Ljava/net/InetSocketAddress;");
|
||||
if(env->ExceptionCheck() || addressField == NULL)
|
||||
{
|
||||
LOGE("Error finding address field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lastSendField = lookup.findField(pppClass, "lastSend", "J");
|
||||
if(env->ExceptionCheck() || lastSendField == NULL)
|
||||
{
|
||||
LOGE("Error finding lastSend field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lastReceiveField = lookup.findField(pppClass, "lastReceive", "J");
|
||||
if(env->ExceptionCheck() || lastReceiveField == NULL)
|
||||
{
|
||||
LOGE("Error finding lastReceive field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
preferredField = lookup.findField(pppClass, "preferred", "Z");
|
||||
if(env->ExceptionCheck() || preferredField == NULL)
|
||||
{
|
||||
LOGE("Error finding preferred field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ppp_constructor = lookup.findMethod(pppClass, "<init>", "()V");
|
||||
if(env->ExceptionCheck() || ppp_constructor == NULL)
|
||||
{
|
||||
LOGE("Error finding PeerPhysicalPath constructor");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobject pppObject = env->NewObject(pppClass, ppp_constructor);
|
||||
if(env->ExceptionCheck() || pppObject == NULL)
|
||||
{
|
||||
LOGE("Error creating PPP object");
|
||||
return NULL; // out of memory
|
||||
}
|
||||
|
||||
jobject addressObject = newInetSocketAddress(env, ppp.address);
|
||||
if(env->ExceptionCheck() || addressObject == NULL) {
|
||||
LOGE("Error creating InetSocketAddress object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
env->SetObjectField(pppObject, addressField, addressObject);
|
||||
env->SetLongField(pppObject, lastSendField, ppp.lastSend);
|
||||
env->SetLongField(pppObject, lastReceiveField, ppp.lastReceive);
|
||||
env->SetBooleanField(pppObject, preferredField, ppp.preferred);
|
||||
|
||||
if(env->ExceptionCheck()) {
|
||||
LOGE("Exception assigning fields to PeerPhysicalPath object");
|
||||
}
|
||||
|
||||
return pppObject;
|
||||
}
|
||||
|
||||
jobject newPeer(JNIEnv *env, const ZT_Peer &peer)
|
||||
{
|
||||
LOGV("newPeer called");
|
||||
|
||||
jclass peerClass = NULL;
|
||||
|
||||
jfieldID addressField = NULL;
|
||||
jfieldID versionMajorField = NULL;
|
||||
jfieldID versionMinorField = NULL;
|
||||
jfieldID versionRevField = NULL;
|
||||
jfieldID latencyField = NULL;
|
||||
jfieldID roleField = NULL;
|
||||
jfieldID pathsField = NULL;
|
||||
|
||||
jmethodID peer_constructor = NULL;
|
||||
|
||||
peerClass = lookup.findClass("com/zerotier/sdk/Peer");
|
||||
if(env->ExceptionCheck() || peerClass == NULL)
|
||||
{
|
||||
LOGE("Error finding Peer class");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addressField = lookup.findField(peerClass, "address", "J");
|
||||
if(env->ExceptionCheck() || addressField == NULL)
|
||||
{
|
||||
LOGE("Error finding address field of Peer object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
versionMajorField = lookup.findField(peerClass, "versionMajor", "I");
|
||||
if(env->ExceptionCheck() || versionMajorField == NULL)
|
||||
{
|
||||
LOGE("Error finding versionMajor field of Peer object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
versionMinorField = lookup.findField(peerClass, "versionMinor", "I");
|
||||
if(env->ExceptionCheck() || versionMinorField == NULL)
|
||||
{
|
||||
LOGE("Error finding versionMinor field of Peer object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
versionRevField = lookup.findField(peerClass, "versionRev", "I");
|
||||
if(env->ExceptionCheck() || versionRevField == NULL)
|
||||
{
|
||||
LOGE("Error finding versionRev field of Peer object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
latencyField = lookup.findField(peerClass, "latency", "I");
|
||||
if(env->ExceptionCheck() || latencyField == NULL)
|
||||
{
|
||||
LOGE("Error finding latency field of Peer object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
roleField = lookup.findField(peerClass, "role", "Lcom/zerotier/sdk/PeerRole;");
|
||||
if(env->ExceptionCheck() || roleField == NULL)
|
||||
{
|
||||
LOGE("Error finding role field of Peer object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pathsField = lookup.findField(peerClass, "paths", "[Lcom/zerotier/sdk/PeerPhysicalPath;");
|
||||
if(env->ExceptionCheck() || pathsField == NULL)
|
||||
{
|
||||
LOGE("Error finding paths field of Peer object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
peer_constructor = lookup.findMethod(peerClass, "<init>", "()V");
|
||||
if(env->ExceptionCheck() || peer_constructor == NULL)
|
||||
{
|
||||
LOGE("Error finding Peer constructor");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobject peerObject = env->NewObject(peerClass, peer_constructor);
|
||||
if(env->ExceptionCheck() || peerObject == NULL)
|
||||
{
|
||||
LOGE("Error creating Peer object");
|
||||
return NULL; // out of memory
|
||||
}
|
||||
|
||||
env->SetLongField(peerObject, addressField, (jlong)peer.address);
|
||||
env->SetIntField(peerObject, versionMajorField, peer.versionMajor);
|
||||
env->SetIntField(peerObject, versionMinorField, peer.versionMinor);
|
||||
env->SetIntField(peerObject, versionRevField, peer.versionRev);
|
||||
env->SetIntField(peerObject, latencyField, peer.latency);
|
||||
env->SetObjectField(peerObject, roleField, createPeerRole(env, peer.role));
|
||||
|
||||
jclass peerPhysicalPathClass = lookup.findClass("com/zerotier/sdk/PeerPhysicalPath");
|
||||
if(env->ExceptionCheck() || peerPhysicalPathClass == NULL)
|
||||
{
|
||||
LOGE("Error finding PeerPhysicalPath class");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobjectArray arrayObject = env->NewObjectArray(
|
||||
peer.pathCount, peerPhysicalPathClass, NULL);
|
||||
if(env->ExceptionCheck() || arrayObject == NULL)
|
||||
{
|
||||
LOGE("Error creating PeerPhysicalPath[] array");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < peer.pathCount; ++i)
|
||||
{
|
||||
jobject path = newPeerPhysicalPath(env, peer.paths[i]);
|
||||
|
||||
env->SetObjectArrayElement(arrayObject, i, path);
|
||||
if(env->ExceptionCheck()) {
|
||||
LOGE("exception assigning PeerPhysicalPath to array");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
env->SetObjectField(peerObject, pathsField, arrayObject);
|
||||
|
||||
return peerObject;
|
||||
}
|
||||
|
||||
jobject newNetworkConfig(JNIEnv *env, const ZT_VirtualNetworkConfig &vnetConfig)
|
||||
{
|
||||
jclass vnetConfigClass = NULL;
|
||||
jmethodID vnetConfig_constructor = NULL;
|
||||
jfieldID nwidField = NULL;
|
||||
jfieldID macField = NULL;
|
||||
jfieldID nameField = NULL;
|
||||
jfieldID statusField = NULL;
|
||||
jfieldID typeField = NULL;
|
||||
jfieldID mtuField = NULL;
|
||||
jfieldID dhcpField = NULL;
|
||||
jfieldID bridgeField = NULL;
|
||||
jfieldID broadcastEnabledField = NULL;
|
||||
jfieldID portErrorField = NULL;
|
||||
jfieldID netconfRevisionField = NULL;
|
||||
jfieldID assignedAddressesField = NULL;
|
||||
jfieldID routesField = NULL;
|
||||
|
||||
vnetConfigClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkConfig");
|
||||
if(vnetConfigClass == NULL)
|
||||
{
|
||||
LOGE("Couldn't find com.zerotier.sdk.VirtualNetworkConfig");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vnetConfig_constructor = lookup.findMethod(
|
||||
vnetConfigClass, "<init>", "()V");
|
||||
if(env->ExceptionCheck() || vnetConfig_constructor == NULL)
|
||||
{
|
||||
LOGE("Couldn't find VirtualNetworkConfig Constructor");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobject vnetConfigObj = env->NewObject(vnetConfigClass, vnetConfig_constructor);
|
||||
if(env->ExceptionCheck() || vnetConfigObj == NULL)
|
||||
{
|
||||
LOGE("Error creating new VirtualNetworkConfig object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nwidField = lookup.findField(vnetConfigClass, "nwid", "J");
|
||||
if(env->ExceptionCheck() || nwidField == NULL)
|
||||
{
|
||||
LOGE("Error getting nwid field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
macField = lookup.findField(vnetConfigClass, "mac", "J");
|
||||
if(env->ExceptionCheck() || macField == NULL)
|
||||
{
|
||||
LOGE("Error getting mac field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nameField = lookup.findField(vnetConfigClass, "name", "Ljava/lang/String;");
|
||||
if(env->ExceptionCheck() || nameField == NULL)
|
||||
{
|
||||
LOGE("Error getting name field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
statusField = lookup.findField(vnetConfigClass, "status", "Lcom/zerotier/sdk/VirtualNetworkStatus;");
|
||||
if(env->ExceptionCheck() || statusField == NULL)
|
||||
{
|
||||
LOGE("Error getting status field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typeField = lookup.findField(vnetConfigClass, "type", "Lcom/zerotier/sdk/VirtualNetworkType;");
|
||||
if(env->ExceptionCheck() || typeField == NULL)
|
||||
{
|
||||
LOGE("Error getting type field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mtuField = lookup.findField(vnetConfigClass, "mtu", "I");
|
||||
if(env->ExceptionCheck() || mtuField == NULL)
|
||||
{
|
||||
LOGE("Error getting mtu field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dhcpField = lookup.findField(vnetConfigClass, "dhcp", "Z");
|
||||
if(env->ExceptionCheck() || dhcpField == NULL)
|
||||
{
|
||||
LOGE("Error getting dhcp field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bridgeField = lookup.findField(vnetConfigClass, "bridge", "Z");
|
||||
if(env->ExceptionCheck() || bridgeField == NULL)
|
||||
{
|
||||
LOGE("Error getting bridge field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
broadcastEnabledField = lookup.findField(vnetConfigClass, "broadcastEnabled", "Z");
|
||||
if(env->ExceptionCheck() || broadcastEnabledField == NULL)
|
||||
{
|
||||
LOGE("Error getting broadcastEnabled field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
portErrorField = lookup.findField(vnetConfigClass, "portError", "I");
|
||||
if(env->ExceptionCheck() || portErrorField == NULL)
|
||||
{
|
||||
LOGE("Error getting portError field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
netconfRevisionField = lookup.findField(vnetConfigClass, "netconfRevision", "J");
|
||||
if(env->ExceptionCheck() || netconfRevisionField == NULL)
|
||||
{
|
||||
LOGE("Error getting netconfRevision field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assignedAddressesField = lookup.findField(vnetConfigClass, "assignedAddresses",
|
||||
"[Ljava/net/InetSocketAddress;");
|
||||
if(env->ExceptionCheck() || assignedAddressesField == NULL)
|
||||
{
|
||||
LOGE("Error getting assignedAddresses field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
routesField = lookup.findField(vnetConfigClass, "routes",
|
||||
"[Lcom/zerotier/sdk/VirtualNetworkRoute;");
|
||||
if(env->ExceptionCheck() || routesField == NULL)
|
||||
{
|
||||
LOGE("Error getting routes field");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
env->SetLongField(vnetConfigObj, nwidField, vnetConfig.nwid);
|
||||
env->SetLongField(vnetConfigObj, macField, vnetConfig.mac);
|
||||
jstring nameStr = env->NewStringUTF(vnetConfig.name);
|
||||
if(env->ExceptionCheck() || nameStr == NULL)
|
||||
{
|
||||
return NULL; // out of memory
|
||||
}
|
||||
env->SetObjectField(vnetConfigObj, nameField, nameStr);
|
||||
|
||||
jobject statusObject = createVirtualNetworkStatus(env, vnetConfig.status);
|
||||
if(env->ExceptionCheck() || statusObject == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
env->SetObjectField(vnetConfigObj, statusField, statusObject);
|
||||
|
||||
jobject typeObject = createVirtualNetworkType(env, vnetConfig.type);
|
||||
if(env->ExceptionCheck() || typeObject == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
env->SetObjectField(vnetConfigObj, typeField, typeObject);
|
||||
|
||||
env->SetIntField(vnetConfigObj, mtuField, (int)vnetConfig.mtu);
|
||||
env->SetBooleanField(vnetConfigObj, dhcpField, vnetConfig.dhcp);
|
||||
env->SetBooleanField(vnetConfigObj, bridgeField, vnetConfig.bridge);
|
||||
env->SetBooleanField(vnetConfigObj, broadcastEnabledField, vnetConfig.broadcastEnabled);
|
||||
env->SetIntField(vnetConfigObj, portErrorField, vnetConfig.portError);
|
||||
|
||||
jclass inetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress");
|
||||
if(env->ExceptionCheck() || inetSocketAddressClass == NULL)
|
||||
{
|
||||
LOGE("Error finding InetSocketAddress class");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobjectArray assignedAddrArrayObj = env->NewObjectArray(
|
||||
vnetConfig.assignedAddressCount, inetSocketAddressClass, NULL);
|
||||
if(env->ExceptionCheck() || assignedAddrArrayObj == NULL)
|
||||
{
|
||||
LOGE("Error creating InetSocketAddress[] array");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < vnetConfig.assignedAddressCount; ++i)
|
||||
{
|
||||
jobject inetAddrObj = newInetSocketAddress(env, vnetConfig.assignedAddresses[i]);
|
||||
env->SetObjectArrayElement(assignedAddrArrayObj, i, inetAddrObj);
|
||||
if(env->ExceptionCheck())
|
||||
{
|
||||
LOGE("Error assigning InetSocketAddress to array");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
env->SetObjectField(vnetConfigObj, assignedAddressesField, assignedAddrArrayObj);
|
||||
|
||||
jclass virtualNetworkRouteClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkRoute");
|
||||
if(env->ExceptionCheck() || virtualNetworkRouteClass == NULL)
|
||||
{
|
||||
LOGE("Error finding VirtualNetworkRoute class");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobjectArray routesArrayObj = env->NewObjectArray(
|
||||
vnetConfig.routeCount, virtualNetworkRouteClass, NULL);
|
||||
if(env->ExceptionCheck() || routesArrayObj == NULL)
|
||||
{
|
||||
LOGE("Error creating VirtualNetworkRoute[] array");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < vnetConfig.routeCount; ++i)
|
||||
{
|
||||
jobject routeObj = newVirtualNetworkRoute(env, vnetConfig.routes[i]);
|
||||
env->SetObjectArrayElement(routesArrayObj, i, routeObj);
|
||||
if(env->ExceptionCheck())
|
||||
{
|
||||
LOGE("Error assigning VirtualNetworkRoute to array");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
env->SetObjectField(vnetConfigObj, routesField, routesArrayObj);
|
||||
|
||||
return vnetConfigObj;
|
||||
}
|
||||
|
||||
jobject newVersion(JNIEnv *env, int major, int minor, int rev)
|
||||
{
|
||||
// create a com.zerotier.sdk.Version object
|
||||
jclass versionClass = NULL;
|
||||
jmethodID versionConstructor = NULL;
|
||||
|
||||
versionClass = lookup.findClass("com/zerotier/sdk/Version");
|
||||
if(env->ExceptionCheck() || versionClass == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
versionConstructor = lookup.findMethod(
|
||||
versionClass, "<init>", "()V");
|
||||
if(env->ExceptionCheck() || versionConstructor == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobject versionObj = env->NewObject(versionClass, versionConstructor);
|
||||
if(env->ExceptionCheck() || versionObj == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// copy data to Version object
|
||||
jfieldID majorField = NULL;
|
||||
jfieldID minorField = NULL;
|
||||
jfieldID revisionField = NULL;
|
||||
|
||||
majorField = lookup.findField(versionClass, "major", "I");
|
||||
if(env->ExceptionCheck() || majorField == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
minorField = lookup.findField(versionClass, "minor", "I");
|
||||
if(env->ExceptionCheck() || minorField == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
revisionField = lookup.findField(versionClass, "revision", "I");
|
||||
if(env->ExceptionCheck() || revisionField == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
env->SetIntField(versionObj, majorField, (jint)major);
|
||||
env->SetIntField(versionObj, minorField, (jint)minor);
|
||||
env->SetIntField(versionObj, revisionField, (jint)rev);
|
||||
|
||||
return versionObj;
|
||||
}
|
||||
|
||||
jobject newVirtualNetworkRoute(JNIEnv *env, const ZT_VirtualNetworkRoute &route)
|
||||
{
|
||||
jclass virtualNetworkRouteClass = NULL;
|
||||
jmethodID routeConstructor = NULL;
|
||||
|
||||
virtualNetworkRouteClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkRoute");
|
||||
if(env->ExceptionCheck() || virtualNetworkRouteClass == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
routeConstructor = lookup.findMethod(virtualNetworkRouteClass, "<init>", "()V");
|
||||
if(env->ExceptionCheck() || routeConstructor == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobject routeObj = env->NewObject(virtualNetworkRouteClass, routeConstructor);
|
||||
if(env->ExceptionCheck() || routeObj == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jfieldID targetField = NULL;
|
||||
jfieldID viaField = NULL;
|
||||
jfieldID flagsField = NULL;
|
||||
jfieldID metricField = NULL;
|
||||
|
||||
targetField = lookup.findField(virtualNetworkRouteClass, "target",
|
||||
"Ljava/net/InetSocketAddress;");
|
||||
if(env->ExceptionCheck() || targetField == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
viaField = lookup.findField(virtualNetworkRouteClass, "via",
|
||||
"Ljava/net/InetSocketAddress;");
|
||||
if(env->ExceptionCheck() || targetField == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flagsField = lookup.findField(virtualNetworkRouteClass, "flags", "I");
|
||||
if(env->ExceptionCheck() || flagsField == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
metricField = lookup.findField(virtualNetworkRouteClass, "metric", "I");
|
||||
if(env->ExceptionCheck() || metricField == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jobject targetObj = newInetSocketAddress(env, route.target);
|
||||
jobject viaObj = newInetSocketAddress(env, route.via);
|
||||
|
||||
env->SetObjectField(routeObj, targetField, targetObj);
|
||||
env->SetObjectField(routeObj, viaField, viaObj);
|
||||
env->SetIntField(routeObj, flagsField, (jint)route.flags);
|
||||
env->SetIntField(routeObj, metricField, (jint)route.metric);
|
||||
|
||||
return routeObj;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
69
zerotierone/java/jni/ZT_jniutils.h
Normal file
69
zerotierone/java/jni/ZT_jniutils.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_jniutils_h_
|
||||
#define ZT_jniutils_h_
|
||||
#include <stdio.h>
|
||||
#include <jni.h>
|
||||
#include <ZeroTierOne.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LOG_TAG "ZeroTierOneJNI"
|
||||
|
||||
#if __ANDROID__
|
||||
#include <android/log.h>
|
||||
#define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
|
||||
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
|
||||
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
|
||||
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
|
||||
#else
|
||||
#define LOGV(...) fprintf(stdout, __VA_ARGS__)
|
||||
#define LOGI(...) fprintf(stdout, __VA_ARGS__)
|
||||
#define LOGD(...) fprintf(stdout, __VA_ARGS__)
|
||||
#define LOGE(...) fprintf(stdout, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
jobject createResultObject(JNIEnv *env, ZT_ResultCode code);
|
||||
jobject createVirtualNetworkStatus(JNIEnv *env, ZT_VirtualNetworkStatus status);
|
||||
jobject createVirtualNetworkType(JNIEnv *env, ZT_VirtualNetworkType type);
|
||||
jobject createEvent(JNIEnv *env, ZT_Event event);
|
||||
jobject createPeerRole(JNIEnv *env, ZT_PeerRole role);
|
||||
jobject createVirtualNetworkConfigOperation(JNIEnv *env, ZT_VirtualNetworkConfigOperation op);
|
||||
|
||||
jobject newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr);
|
||||
jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr);
|
||||
|
||||
jobject newMulticastGroup(JNIEnv *env, const ZT_MulticastGroup &mc);
|
||||
|
||||
jobject newPeer(JNIEnv *env, const ZT_Peer &peer);
|
||||
jobject newPeerPhysicalPath(JNIEnv *env, const ZT_PeerPhysicalPath &ppp);
|
||||
|
||||
jobject newNetworkConfig(JNIEnv *env, const ZT_VirtualNetworkConfig &config);
|
||||
|
||||
jobject newVersion(JNIEnv *env, int major, int minor, int rev);
|
||||
|
||||
jobject newVirtualNetworkRoute(JNIEnv *env, const ZT_VirtualNetworkRoute &route);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1381
zerotierone/java/jni/com_zerotierone_sdk_Node.cpp
Normal file
1381
zerotierone/java/jni/com_zerotierone_sdk_Node.cpp
Normal file
File diff suppressed because it is too large
Load Diff
133
zerotierone/java/jni/com_zerotierone_sdk_Node.h
Normal file
133
zerotierone/java/jni/com_zerotierone_sdk_Node.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_zerotier_sdk_Node */
|
||||
|
||||
#ifndef _Included_com_zerotierone_sdk_Node
|
||||
#define _Included_com_zerotierone_sdk_Node
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: node_init
|
||||
* Signature: (J)Lcom/zerotier/sdk/ResultCode;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: node_delete
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_zerotier_sdk_Node_node_1delete
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: processVirtualNetworkFrame
|
||||
* Signature: (JJJJJII[B[J)Lcom/zerotier/sdk/ResultCode;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame
|
||||
(JNIEnv *, jobject, jlong, jlong, jlong, jlong, jlong, jint, jint, jbyteArray, jlongArray);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: processWirePacket
|
||||
* Signature: (JJLjava/net/InetSockAddress;Ljava/net/InetSockAddress;[B[J)Lcom/zerotier/sdk/ResultCode;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket
|
||||
(JNIEnv *, jobject, jlong, jlong, jobject, jobject, jbyteArray, jlongArray);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: processBackgroundTasks
|
||||
* Signature: (JJ[J)Lcom/zerotier/sdk/ResultCode;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processBackgroundTasks
|
||||
(JNIEnv *, jobject, jlong, jlong, jlongArray);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: join
|
||||
* Signature: (JJ)Lcom/zerotier/sdk/ResultCode;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_join
|
||||
(JNIEnv *, jobject, jlong, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: leave
|
||||
* Signature: (JJ)Lcom/zerotier/sdk/ResultCode;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_leave
|
||||
(JNIEnv *, jobject, jlong, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: multicastSubscribe
|
||||
* Signature: (JJJJ)Lcom/zerotier/sdk/ResultCode;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastSubscribe
|
||||
(JNIEnv *, jobject, jlong, jlong, jlong, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: multicastUnsubscribe
|
||||
* Signature: (JJJJ)Lcom/zerotier/sdk/ResultCode;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastUnsubscribe
|
||||
(JNIEnv *, jobject, jlong, jlong, jlong, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: address
|
||||
* Signature: (J)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_com_zerotier_sdk_Node_address
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: status
|
||||
* Signature: (J)Lcom/zerotier/sdk/NodeStatus;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_status
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: networkConfig
|
||||
* Signature: (JJ)Lcom/zerotier/sdk/VirtualNetworkConfig;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_networkConfig
|
||||
(JNIEnv *, jobject, jlong, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: version
|
||||
* Signature: ()Lcom/zerotier/sdk/Version;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_version
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: peers
|
||||
* Signature: (J)[Lcom/zerotier/sdk/Peer;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_peers
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_zerotier_sdk_Node
|
||||
* Method: networks
|
||||
* Signature: (J)[Lcom/zerotier/sdk/VirtualNetworkConfig;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networks
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
package com.zerotier.sdk;
|
||||
|
||||
public interface DataStoreGetListener {
|
||||
|
||||
/**
|
||||
* Function to get an object from the data store
|
||||
*
|
||||
* <p>Object names can contain forward slash (/) path separators. They will
|
||||
* never contain .. or backslash (\), so this is safe to map as a Unix-style
|
||||
* path if the underlying storage permits. For security reasons we recommend
|
||||
* returning errors if .. or \ are used.</p>
|
||||
*
|
||||
* <p>The function must return the actual number of bytes read. If the object
|
||||
* doesn't exist, it should return -1. -2 should be returned on other errors
|
||||
* such as errors accessing underlying storage.</p>
|
||||
*
|
||||
* <p>If the read doesn't fit in the buffer, the max number of bytes should be
|
||||
* read. The caller may call the function multiple times to read the whole
|
||||
* object.</p>
|
||||
*
|
||||
* @param name Name of the object in the data store
|
||||
* @param out_buffer buffer to put the object in
|
||||
* @param bufferIndex index in the object to start reading
|
||||
* @param out_objectSize long[1] to be set to the actual size of the object if it exists.
|
||||
* @return the actual number of bytes read.
|
||||
*/
|
||||
public long onDataStoreGet(
|
||||
String name,
|
||||
byte[] out_buffer,
|
||||
long bufferIndex,
|
||||
long[] out_objectSize);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
package com.zerotier.sdk;
|
||||
|
||||
public interface DataStorePutListener {
|
||||
|
||||
/**
|
||||
* Function to store an object in the data store
|
||||
*
|
||||
* <p>If secure is true, the file should be set readable and writable only
|
||||
* to the user running ZeroTier One. What this means is platform-specific.</p>
|
||||
*
|
||||
* <p>Name semantics are the same as {@link DataStoreGetListener}. This must return
|
||||
* zero on success. You can return any OS-specific error code on failure, as these
|
||||
* may be visible in logs or error messages and might aid in debugging.</p>
|
||||
*
|
||||
* @param name Object name
|
||||
* @param buffer data to store
|
||||
* @param secure set to user read/write only.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
public int onDataStorePut(
|
||||
String name,
|
||||
byte[] buffer,
|
||||
boolean secure);
|
||||
|
||||
/**
|
||||
* Function to delete an object from the data store
|
||||
*
|
||||
* @param name Object name
|
||||
* @return 0 on success.
|
||||
*/
|
||||
public int onDelete(
|
||||
String name);
|
||||
}
|
||||
98
zerotierone/java/src/com/zerotier/sdk/Event.java
Normal file
98
zerotierone/java/src/com/zerotier/sdk/Event.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
public enum Event {
|
||||
/**
|
||||
* Node has been initialized
|
||||
*
|
||||
* This is the first event generated, and is always sent. It may occur
|
||||
* before Node's constructor returns.
|
||||
*/
|
||||
EVENT_UP,
|
||||
|
||||
/**
|
||||
* Node is offline -- network does not seem to be reachable by any available strategy
|
||||
*/
|
||||
EVENT_OFFLINE,
|
||||
|
||||
/**
|
||||
* Node is online -- at least one upstream node appears reachable
|
||||
*
|
||||
* Meta-data: none
|
||||
*/
|
||||
EVENT_ONLINE,
|
||||
|
||||
/**
|
||||
* Node is shutting down
|
||||
*
|
||||
* <p>This is generated within Node's destructor when it is being shut down.
|
||||
* It's done for convenience, since cleaning up other state in the event
|
||||
* handler may appear more idiomatic.</p>
|
||||
*/
|
||||
EVENT_DOWN,
|
||||
|
||||
/**
|
||||
* Your identity has collided with another node's ZeroTier address
|
||||
*
|
||||
* <p>This happens if two different public keys both hash (via the algorithm
|
||||
* in Identity::generate()) to the same 40-bit ZeroTier address.</p>
|
||||
*
|
||||
* <p>This is something you should "never" see, where "never" is defined as
|
||||
* once per 2^39 new node initializations / identity creations. If you do
|
||||
* see it, you're going to see it very soon after a node is first
|
||||
* initialized.</p>
|
||||
*
|
||||
* <p>This is reported as an event rather than a return code since it's
|
||||
* detected asynchronously via error messages from authoritative nodes.</p>
|
||||
*
|
||||
* <p>If this occurs, you must shut down and delete the node, delete the
|
||||
* identity.secret record/file from the data store, and restart to generate
|
||||
* a new identity. If you don't do this, you will not be able to communicate
|
||||
* with other nodes.</p>
|
||||
*
|
||||
* <p>We'd automate this process, but we don't think silently deleting
|
||||
* private keys or changing our address without telling the calling code
|
||||
* is good form. It violates the principle of least surprise.</p>
|
||||
*
|
||||
* <p>You can technically get away with not handling this, but we recommend
|
||||
* doing so in a mature reliable application. Besides, handling this
|
||||
* condition is a good way to make sure it never arises. It's like how
|
||||
* umbrellas prevent rain and smoke detectors prevent fires. They do, right?</p>
|
||||
*/
|
||||
EVENT_FATAL_ERROR_IDENTITY_COLLISION,
|
||||
|
||||
/**
|
||||
* Trace (debugging) message
|
||||
*
|
||||
* <p>These events are only generated if this is a TRACE-enabled build.</p>
|
||||
*
|
||||
* <p>Meta-data: {@link String}, TRACE message</p>
|
||||
*/
|
||||
EVENT_TRACE
|
||||
}
|
||||
52
zerotierone/java/src/com/zerotier/sdk/EventListener.java
Normal file
52
zerotierone/java/src/com/zerotier/sdk/EventListener.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.lang.String;
|
||||
|
||||
/**
|
||||
* Interface to handle callbacks for ZeroTier One events.
|
||||
*/
|
||||
public interface EventListener {
|
||||
/**
|
||||
* Callback for events with no other associated metadata
|
||||
*
|
||||
* @param event {@link Event} enum
|
||||
*/
|
||||
public void onEvent(Event event);
|
||||
|
||||
/**
|
||||
* Trace messages
|
||||
*
|
||||
* <p>These events are only generated if the underlying ZeroTierOne SDK is a TRACE-enabled build.</p>
|
||||
*
|
||||
* @param message the trace message
|
||||
*/
|
||||
public void onTrace(String message);
|
||||
}
|
||||
93
zerotierone/java/src/com/zerotier/sdk/NativeUtils.java
Normal file
93
zerotierone/java/src/com/zerotier/sdk/NativeUtils.java
Normal file
@@ -0,0 +1,93 @@
|
||||
package com.zerotier.sdk;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Simple library class for working with JNI (Java Native Interface)
|
||||
*
|
||||
* @see http://adamheinrich.com/2012/how-to-load-native-jni-library-from-jar
|
||||
*
|
||||
* @author Adam Heirnich <adam@adamh.cz>, http://www.adamh.cz
|
||||
*/
|
||||
public class NativeUtils {
|
||||
|
||||
/**
|
||||
* Private constructor - this class will never be instanced
|
||||
*/
|
||||
private NativeUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads library from current JAR archive
|
||||
*
|
||||
* The file from JAR is copied into system temporary directory and then loaded. The temporary file is deleted after exiting.
|
||||
* Method uses String as filename because the pathname is "abstract", not system-dependent.
|
||||
*
|
||||
* @param filename The filename inside JAR as absolute path (beginning with '/'), e.g. /package/File.ext
|
||||
* @throws IOException If temporary file creation or read/write operation fails
|
||||
* @throws IllegalArgumentException If source file (param path) does not exist
|
||||
* @throws IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters (restriction of {@see File#createTempFile(java.lang.String, java.lang.String)}).
|
||||
*/
|
||||
public static void loadLibraryFromJar(String path) throws IOException {
|
||||
|
||||
if (!path.startsWith("/")) {
|
||||
throw new IllegalArgumentException("The path has to be absolute (start with '/').");
|
||||
}
|
||||
|
||||
// Obtain filename from path
|
||||
String[] parts = path.split("/");
|
||||
String filename = (parts.length > 1) ? parts[parts.length - 1] : null;
|
||||
|
||||
// Split filename to prexif and suffix (extension)
|
||||
String prefix = "";
|
||||
String suffix = null;
|
||||
if (filename != null) {
|
||||
parts = filename.split("\\.", 2);
|
||||
prefix = parts[0];
|
||||
suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; // Thanks, davs! :-)
|
||||
}
|
||||
|
||||
// Check if the filename is okay
|
||||
if (filename == null || prefix.length() < 3) {
|
||||
throw new IllegalArgumentException("The filename has to be at least 3 characters long.");
|
||||
}
|
||||
|
||||
// Prepare temporary file
|
||||
File temp = File.createTempFile(prefix, suffix);
|
||||
temp.deleteOnExit();
|
||||
|
||||
if (!temp.exists()) {
|
||||
throw new FileNotFoundException("File " + temp.getAbsolutePath() + " does not exist.");
|
||||
}
|
||||
|
||||
// Prepare buffer for data copying
|
||||
byte[] buffer = new byte[1024];
|
||||
int readBytes;
|
||||
|
||||
// Open and check input stream
|
||||
InputStream is = NativeUtils.class.getResourceAsStream(path);
|
||||
if (is == null) {
|
||||
throw new FileNotFoundException("File " + path + " was not found inside JAR.");
|
||||
}
|
||||
|
||||
// Open output stream and copy data between source file in JAR and the temporary file
|
||||
OutputStream os = new FileOutputStream(temp);
|
||||
try {
|
||||
while ((readBytes = is.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, readBytes);
|
||||
}
|
||||
} finally {
|
||||
// If read/write fails, close streams safely before throwing an exception
|
||||
os.close();
|
||||
is.close();
|
||||
}
|
||||
|
||||
// Finally, load the library
|
||||
System.load(temp.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
434
zerotierone/java/src/com/zerotier/sdk/Node.java
Normal file
434
zerotierone/java/src/com/zerotier/sdk/Node.java
Normal file
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A ZeroTier One node
|
||||
*/
|
||||
public class Node {
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("ZeroTierOneJNI");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
try {
|
||||
if(System.getProperty("os.name").startsWith("Windows")) {
|
||||
System.out.println("Arch: " + System.getProperty("sun.arch.data.model"));
|
||||
if(System.getProperty("sun.arch.data.model").equals("64")) {
|
||||
NativeUtils.loadLibraryFromJar("/lib/ZeroTierOneJNI_win64.dll");
|
||||
} else {
|
||||
NativeUtils.loadLibraryFromJar("/lib/ZeroTierOneJNI_win32.dll");
|
||||
}
|
||||
} else if(System.getProperty("os.name").startsWith("Mac")) {
|
||||
NativeUtils.loadLibraryFromJar("/lib/libZeroTierOneJNI.jnilib");
|
||||
} else {
|
||||
// TODO: Linux
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String TAG = "NODE";
|
||||
|
||||
/**
|
||||
* Node ID for JNI purposes.
|
||||
* Currently set to the now value passed in at the constructor
|
||||
*
|
||||
* -1 if the node has already been closed
|
||||
*/
|
||||
private long nodeId;
|
||||
|
||||
private final DataStoreGetListener getListener;
|
||||
private final DataStorePutListener putListener;
|
||||
private final PacketSender sender;
|
||||
private final EventListener eventListener;
|
||||
private final VirtualNetworkFrameListener frameListener;
|
||||
private final VirtualNetworkConfigListener configListener;
|
||||
|
||||
/**
|
||||
* Create a new ZeroTier One node
|
||||
*
|
||||
* <p>Note that this can take a few seconds the first time it's called, as it
|
||||
* will generate an identity.</p>
|
||||
*
|
||||
* @param now Current clock in milliseconds
|
||||
* @param getListener User written instance of the {@link DataStoreGetListener} interface called to get objects from persistent storage. This instance must be unique per Node object.
|
||||
* @param putListener User written intstance of the {@link DataStorePutListener} interface called to put objects in persistent storage. This instance must be unique per Node object.
|
||||
* @param sender
|
||||
* @param eventListener User written instance of the {@link EventListener} interface to receive status updates and non-fatal error notices. This instance must be unique per Node object.
|
||||
* @param frameListener
|
||||
* @param configListener User written instance of the {@link VirtualNetworkConfigListener} interface to be called when virtual LANs are created, deleted, or their config parameters change. This instance must be unique per Node object.
|
||||
*/
|
||||
public Node(long now,
|
||||
DataStoreGetListener getListener,
|
||||
DataStorePutListener putListener,
|
||||
PacketSender sender,
|
||||
EventListener eventListener,
|
||||
VirtualNetworkFrameListener frameListener,
|
||||
VirtualNetworkConfigListener configListener) throws NodeException
|
||||
{
|
||||
this.nodeId = now;
|
||||
|
||||
this.getListener = getListener;
|
||||
this.putListener = putListener;
|
||||
this.sender = sender;
|
||||
this.eventListener = eventListener;
|
||||
this.frameListener = frameListener;
|
||||
this.configListener = configListener;
|
||||
|
||||
ResultCode rc = node_init(now);
|
||||
if(rc != ResultCode.RESULT_OK)
|
||||
{
|
||||
// TODO: Throw Exception
|
||||
throw new NodeException(rc.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close this Node.
|
||||
*
|
||||
* <p>The Node object can no longer be used once this method is called.</p>
|
||||
*/
|
||||
public void close() {
|
||||
if(nodeId != -1) {
|
||||
node_delete(nodeId);
|
||||
nodeId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a frame from a virtual network port
|
||||
*
|
||||
* @param now Current clock in milliseconds
|
||||
* @param nwid ZeroTier 64-bit virtual network ID
|
||||
* @param sourceMac Source MAC address (least significant 48 bits)
|
||||
* @param destMac Destination MAC address (least significant 48 bits)
|
||||
* @param etherType 16-bit Ethernet frame type
|
||||
* @param vlanId 10-bit VLAN ID or 0 if none
|
||||
* @param frameData Frame payload data
|
||||
* @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks()
|
||||
* @return OK (0) or error code if a fatal error condition has occurred
|
||||
*/
|
||||
public ResultCode processVirtualNetworkFrame(
|
||||
long now,
|
||||
long nwid,
|
||||
long sourceMac,
|
||||
long destMac,
|
||||
int etherType,
|
||||
int vlanId,
|
||||
byte[] frameData,
|
||||
long[] nextBackgroundTaskDeadline) {
|
||||
return processVirtualNetworkFrame(
|
||||
nodeId, now, nwid, sourceMac, destMac, etherType, vlanId,
|
||||
frameData, nextBackgroundTaskDeadline);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a packet received from the physical wire
|
||||
*
|
||||
* @param now Current clock in milliseconds
|
||||
* @param remoteAddress Origin of packet
|
||||
* @param packetData Packet data
|
||||
* @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks()
|
||||
* @return OK (0) or error code if a fatal error condition has occurred
|
||||
*/
|
||||
public ResultCode processWirePacket(
|
||||
long now,
|
||||
InetSocketAddress localAddress,
|
||||
InetSocketAddress remoteAddress,
|
||||
byte[] packetData,
|
||||
long[] nextBackgroundTaskDeadline) {
|
||||
return processWirePacket(
|
||||
nodeId, now, localAddress, remoteAddress, packetData,
|
||||
nextBackgroundTaskDeadline);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform periodic background operations
|
||||
*
|
||||
* @param now Current clock in milliseconds
|
||||
* @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks()
|
||||
* @return OK (0) or error code if a fatal error condition has occurred
|
||||
*/
|
||||
public ResultCode processBackgroundTasks(long now, long[] nextBackgroundTaskDeadline) {
|
||||
return processBackgroundTasks(nodeId, now, nextBackgroundTaskDeadline);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join a network
|
||||
*
|
||||
* <p>This may generate calls to the port config callback before it returns,
|
||||
* or these may be deffered if a netconf is not available yet.</p>
|
||||
*
|
||||
* <p>If we are already a member of the network, nothing is done and OK is
|
||||
* returned.</p>
|
||||
*
|
||||
* @param nwid 64-bit ZeroTier network ID
|
||||
* @return OK (0) or error code if a fatal error condition has occurred
|
||||
*/
|
||||
public ResultCode join(long nwid) {
|
||||
return join(nodeId, nwid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave a network
|
||||
*
|
||||
* <p>If a port has been configured for this network this will generate a call
|
||||
* to the port config callback with a NULL second parameter to indicate that
|
||||
* the port is now deleted.</p>
|
||||
*
|
||||
* @param nwid 64-bit network ID
|
||||
* @return OK (0) or error code if a fatal error condition has occurred
|
||||
*/
|
||||
public ResultCode leave(long nwid) {
|
||||
return leave(nodeId, nwid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to an Ethernet multicast group
|
||||
*
|
||||
* <p>For IPv4 ARP, the implementation must subscribe to 0xffffffffffff (the
|
||||
* broadcast address) but with an ADI equal to each IPv4 address in host
|
||||
* byte order. This converts ARP from a non-scalable broadcast protocol to
|
||||
* a scalable multicast protocol with perfect address specificity.</p>
|
||||
*
|
||||
* <p>If this is not done, ARP will not work reliably.</p>
|
||||
*
|
||||
* <p>Multiple calls to subscribe to the same multicast address will have no
|
||||
* effect. It is perfectly safe to do this.</p>
|
||||
*
|
||||
* <p>This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.</p>
|
||||
*
|
||||
* @param nwid 64-bit network ID
|
||||
* @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits)
|
||||
* @return OK (0) or error code if a fatal error condition has occurred
|
||||
*/
|
||||
public ResultCode multicastSubscribe(
|
||||
long nwid,
|
||||
long multicastGroup) {
|
||||
return multicastSubscribe(nodeId, nwid, multicastGroup, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to an Ethernet multicast group
|
||||
*
|
||||
* <p>ADI stands for additional distinguishing information. This defaults to zero
|
||||
* and is rarely used. Right now its only use is to enable IPv4 ARP to scale,
|
||||
* and this must be done.</p>
|
||||
*
|
||||
* <p>For IPv4 ARP, the implementation must subscribe to 0xffffffffffff (the
|
||||
* broadcast address) but with an ADI equal to each IPv4 address in host
|
||||
* byte order. This converts ARP from a non-scalable broadcast protocol to
|
||||
* a scalable multicast protocol with perfect address specificity.</p>
|
||||
*
|
||||
* <p>If this is not done, ARP will not work reliably.</p>
|
||||
*
|
||||
* <p>Multiple calls to subscribe to the same multicast address will have no
|
||||
* effect. It is perfectly safe to do this.</p>
|
||||
*
|
||||
* <p>This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.</p>
|
||||
*
|
||||
* @param nwid 64-bit network ID
|
||||
* @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits)
|
||||
* @param multicastAdi Multicast ADI (least significant 32 bits only, default: 0)
|
||||
* @return OK (0) or error code if a fatal error condition has occurred
|
||||
*/
|
||||
public ResultCode multicastSubscribe(
|
||||
long nwid,
|
||||
long multicastGroup,
|
||||
long multicastAdi) {
|
||||
return multicastSubscribe(nodeId, nwid, multicastGroup, multicastAdi);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unsubscribe from an Ethernet multicast group (or all groups)
|
||||
*
|
||||
* <p>If multicastGroup is zero (0), this will unsubscribe from all groups. If
|
||||
* you are not subscribed to a group this has no effect.</p>
|
||||
*
|
||||
* <p>This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.</p>
|
||||
*
|
||||
* @param nwid 64-bit network ID
|
||||
* @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits)
|
||||
* @return OK (0) or error code if a fatal error condition has occurred
|
||||
*/
|
||||
public ResultCode multicastUnsubscribe(
|
||||
long nwid,
|
||||
long multicastGroup) {
|
||||
return multicastUnsubscribe(nodeId, nwid, multicastGroup, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from an Ethernet multicast group (or all groups)
|
||||
*
|
||||
* <p>If multicastGroup is zero (0), this will unsubscribe from all groups. If
|
||||
* you are not subscribed to a group this has no effect.</p>
|
||||
*
|
||||
* <p>This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.</p>
|
||||
*
|
||||
* <p>ADI stands for additional distinguishing information. This defaults to zero
|
||||
* and is rarely used. Right now its only use is to enable IPv4 ARP to scale,
|
||||
* and this must be done.</p>
|
||||
*
|
||||
* @param nwid 64-bit network ID
|
||||
* @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits)
|
||||
* @param multicastAdi Multicast ADI (least significant 32 bits only, default: 0)
|
||||
* @return OK (0) or error code if a fatal error condition has occurred
|
||||
*/
|
||||
public ResultCode multicastUnsubscribe(
|
||||
long nwid,
|
||||
long multicastGroup,
|
||||
long multicastAdi) {
|
||||
return multicastUnsubscribe(nodeId, nwid, multicastGroup, multicastAdi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's 40-bit ZeroTier address
|
||||
*
|
||||
* @return ZeroTier address (least significant 40 bits of 64-bit int)
|
||||
*/
|
||||
public long address() {
|
||||
return address(nodeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status of this node
|
||||
*
|
||||
* @return @{link NodeStatus} struct with the current node status.
|
||||
*/
|
||||
public NodeStatus status() {
|
||||
return status(nodeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of known peer nodes
|
||||
*
|
||||
* @return List of known peers or NULL on failure
|
||||
*/
|
||||
public Peer[] peers() {
|
||||
return peers(nodeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status of a virtual network
|
||||
*
|
||||
* @param nwid 64-bit network ID
|
||||
* @return {@link VirtualNetworkConfig} or NULL if we are not a member of this network
|
||||
*/
|
||||
public VirtualNetworkConfig networkConfig(long nwid) {
|
||||
return networkConfig(nodeId, nwid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate and get status of all networks
|
||||
*
|
||||
* @return List of networks or NULL on failure
|
||||
*/
|
||||
public VirtualNetworkConfig[] networks() {
|
||||
return networks(nodeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ZeroTier One version
|
||||
*
|
||||
* @return {@link Version} object with ZeroTierOne version information.
|
||||
*/
|
||||
public Version getVersion() {
|
||||
return version();
|
||||
}
|
||||
|
||||
//
|
||||
// function declarations for JNI
|
||||
//
|
||||
private native ResultCode node_init(long now);
|
||||
|
||||
private native void node_delete(long nodeId);
|
||||
|
||||
private native ResultCode processVirtualNetworkFrame(
|
||||
long nodeId,
|
||||
long now,
|
||||
long nwid,
|
||||
long sourceMac,
|
||||
long destMac,
|
||||
int etherType,
|
||||
int vlanId,
|
||||
byte[] frameData,
|
||||
long[] nextBackgroundTaskDeadline);
|
||||
|
||||
private native ResultCode processWirePacket(
|
||||
long nodeId,
|
||||
long now,
|
||||
InetSocketAddress localAddress,
|
||||
InetSocketAddress remoteAddress,
|
||||
byte[] packetData,
|
||||
long[] nextBackgroundTaskDeadline);
|
||||
|
||||
private native ResultCode processBackgroundTasks(
|
||||
long nodeId,
|
||||
long now,
|
||||
long[] nextBackgroundTaskDeadline);
|
||||
|
||||
private native ResultCode join(long nodeId, long nwid);
|
||||
|
||||
private native ResultCode leave(long nodeId, long nwid);
|
||||
|
||||
private native ResultCode multicastSubscribe(
|
||||
long nodeId,
|
||||
long nwid,
|
||||
long multicastGroup,
|
||||
long multicastAdi);
|
||||
|
||||
private native ResultCode multicastUnsubscribe(
|
||||
long nodeId,
|
||||
long nwid,
|
||||
long multicastGroup,
|
||||
long multicastAdi);
|
||||
|
||||
private native long address(long nodeId);
|
||||
|
||||
private native NodeStatus status(long nodeId);
|
||||
|
||||
private native VirtualNetworkConfig networkConfig(long nodeId, long nwid);
|
||||
|
||||
private native Version version();
|
||||
|
||||
private native Peer[] peers(long nodeId);
|
||||
|
||||
private native VirtualNetworkConfig[] networks(long nodeId);
|
||||
}
|
||||
36
zerotierone/java/src/com/zerotier/sdk/NodeException.java
Normal file
36
zerotierone/java/src/com/zerotier/sdk/NodeException.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
import java.lang.RuntimeException;
|
||||
|
||||
public class NodeException extends RuntimeException {
|
||||
public NodeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
69
zerotierone/java/src/com/zerotier/sdk/NodeStatus.java
Normal file
69
zerotierone/java/src/com/zerotier/sdk/NodeStatus.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
public final class NodeStatus {
|
||||
private long address;
|
||||
private String publicIdentity;
|
||||
private String secretIdentity;
|
||||
private boolean online;
|
||||
|
||||
private NodeStatus() {}
|
||||
|
||||
/**
|
||||
* 40-bit ZeroTier address of this node
|
||||
*/
|
||||
public final long getAddres() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public identity in string-serialized form (safe to send to others)
|
||||
*
|
||||
* <p>This identity will remain valid as long as the node exists.</p>
|
||||
*/
|
||||
public final String getPublicIdentity() {
|
||||
return publicIdentity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full identity including secret key in string-serialized form
|
||||
*
|
||||
* <p>This identity will remain valid as long as the node exists.</p>
|
||||
*/
|
||||
public final String getSecretIdentity() {
|
||||
return secretIdentity;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if some kind of connectivity appears available
|
||||
*/
|
||||
public final boolean isOnline() {
|
||||
return online;
|
||||
}
|
||||
}
|
||||
50
zerotierone/java/src/com/zerotier/sdk/PacketSender.java
Normal file
50
zerotierone/java/src/com/zerotier/sdk/PacketSender.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
package com.zerotier.sdk;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
|
||||
public interface PacketSender {
|
||||
/**
|
||||
* Function to send a ZeroTier packet out over the wire
|
||||
*
|
||||
* <p>The function must return zero on success and may return any error code
|
||||
* on failure. Note that success does not (of course) guarantee packet
|
||||
* delivery. It only means that the packet appears to have been sent.</p>
|
||||
*
|
||||
* @param localAddr {@link InetSocketAddress} to send from. Set to null if not specified.
|
||||
* @param remoteAddr {@link InetSocketAddress} to send to
|
||||
* @param packetData data to send
|
||||
* @return 0 on success, any error code on failure.
|
||||
*/
|
||||
public int onSendPacketRequested(
|
||||
InetSocketAddress localAddr,
|
||||
InetSocketAddress remoteAddr,
|
||||
byte[] packetData,
|
||||
int ttl);
|
||||
}
|
||||
94
zerotierone/java/src/com/zerotier/sdk/Peer.java
Normal file
94
zerotierone/java/src/com/zerotier/sdk/Peer.java
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Peer status result
|
||||
*/
|
||||
public final class Peer {
|
||||
private long address;
|
||||
private int versionMajor;
|
||||
private int versionMinor;
|
||||
private int versionRev;
|
||||
private int latency;
|
||||
private PeerRole role;
|
||||
private PeerPhysicalPath[] paths;
|
||||
|
||||
private Peer() {}
|
||||
|
||||
/**
|
||||
* ZeroTier address (40 bits)
|
||||
*/
|
||||
public final long address() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote major version or -1 if not known
|
||||
*/
|
||||
public final int versionMajor() {
|
||||
return versionMajor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote minor version or -1 if not known
|
||||
*/
|
||||
public final int versionMinor() {
|
||||
return versionMinor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote revision or -1 if not known
|
||||
*/
|
||||
public final int versionRev() {
|
||||
return versionRev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Last measured latency in milliseconds or zero if unknown
|
||||
*/
|
||||
public final int latency() {
|
||||
return latency;
|
||||
}
|
||||
|
||||
/**
|
||||
* What trust hierarchy role does this device have?
|
||||
*/
|
||||
public final PeerRole role() {
|
||||
return role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Known network paths to peer
|
||||
*/
|
||||
public final PeerPhysicalPath[] paths() {
|
||||
return paths;
|
||||
}
|
||||
}
|
||||
78
zerotierone/java/src/com/zerotier/sdk/PeerPhysicalPath.java
Normal file
78
zerotierone/java/src/com/zerotier/sdk/PeerPhysicalPath.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Physical network path to a peer
|
||||
*/
|
||||
public final class PeerPhysicalPath {
|
||||
private InetSocketAddress address;
|
||||
private long lastSend;
|
||||
private long lastReceive;
|
||||
private boolean fixed;
|
||||
private boolean preferred;
|
||||
|
||||
private PeerPhysicalPath() {}
|
||||
|
||||
/**
|
||||
* Address of endpoint
|
||||
*/
|
||||
public final InetSocketAddress address() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time of last send in milliseconds or 0 for never
|
||||
*/
|
||||
public final long lastSend() {
|
||||
return lastSend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time of last receive in milliseconds or 0 for never
|
||||
*/
|
||||
public final long lastReceive() {
|
||||
return lastReceive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is path fixed? (i.e. not learned, static)
|
||||
*/
|
||||
public final boolean isFixed() {
|
||||
return fixed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is path preferred?
|
||||
*/
|
||||
public final boolean isPreferred() {
|
||||
return preferred;
|
||||
}
|
||||
}
|
||||
45
zerotierone/java/src/com/zerotier/sdk/PeerRole.java
Normal file
45
zerotierone/java/src/com/zerotier/sdk/PeerRole.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
public enum PeerRole {
|
||||
/**
|
||||
* An ordinary node
|
||||
*/
|
||||
PEER_ROLE_LEAF,
|
||||
|
||||
/**
|
||||
* moon root
|
||||
*/
|
||||
PEER_ROLE_MOON,
|
||||
|
||||
/**
|
||||
* planetary root
|
||||
*/
|
||||
PEER_ROLE_PLANET
|
||||
}
|
||||
74
zerotierone/java/src/com/zerotier/sdk/ResultCode.java
Normal file
74
zerotierone/java/src/com/zerotier/sdk/ResultCode.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
/**
|
||||
* Function return code: OK (0) or error results
|
||||
*
|
||||
* <p>Use {@link ResultCode#isFatal) to check for a fatal error. If a fatal error
|
||||
* occurs, the node should be considered to not be working correctly. These
|
||||
* indicate serious problems like an inaccessible data store or a compile
|
||||
* problem.</p>
|
||||
*/
|
||||
public enum ResultCode {
|
||||
/**
|
||||
* Operation completed normally
|
||||
*/
|
||||
RESULT_OK(0),
|
||||
|
||||
// Fatal errors (> 0, < 1000)
|
||||
/**
|
||||
* Ran out of memory
|
||||
*/
|
||||
RESULT_FATAL_ERROR_OUT_OF_MEMORY(1),
|
||||
|
||||
/**
|
||||
* Data store is not writable or has failed
|
||||
*/
|
||||
RESULT_FATAL_ERROR_DATA_STORE_FAILED(2),
|
||||
|
||||
/**
|
||||
* Internal error (e.g. unexpected exception indicating bug or build problem)
|
||||
*/
|
||||
RESULT_FATAL_ERROR_INTERNAL(3),
|
||||
|
||||
// non-fatal errors
|
||||
|
||||
/**
|
||||
* Network ID not valid
|
||||
*/
|
||||
RESULT_ERROR_NETWORK_NOT_FOUND(1000);
|
||||
|
||||
private final int id;
|
||||
ResultCode(int id) { this.id = id; }
|
||||
public int getValue() { return id; }
|
||||
|
||||
public boolean isFatal(int id) {
|
||||
return (id > 0 && id < 1000);
|
||||
}
|
||||
}
|
||||
36
zerotierone/java/src/com/zerotier/sdk/Version.java
Normal file
36
zerotierone/java/src/com/zerotier/sdk/Version.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
public final class Version {
|
||||
private Version() {}
|
||||
|
||||
public int major = 0;
|
||||
public int minor = 0;
|
||||
public int revision = 0;
|
||||
}
|
||||
210
zerotierone/java/src/com/zerotier/sdk/VirtualNetworkConfig.java
Normal file
210
zerotierone/java/src/com/zerotier/sdk/VirtualNetworkConfig.java
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
import java.lang.Comparable;
|
||||
import java.lang.Override;
|
||||
import java.lang.String;
|
||||
import java.util.ArrayList;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public final class VirtualNetworkConfig implements Comparable<VirtualNetworkConfig> {
|
||||
public static final int MAX_MULTICAST_SUBSCRIPTIONS = 4096;
|
||||
public static final int ZT_MAX_ZT_ASSIGNED_ADDRESSES = 16;
|
||||
|
||||
private long nwid;
|
||||
private long mac;
|
||||
private String name;
|
||||
private VirtualNetworkStatus status;
|
||||
private VirtualNetworkType type;
|
||||
private int mtu;
|
||||
private boolean dhcp;
|
||||
private boolean bridge;
|
||||
private boolean broadcastEnabled;
|
||||
private int portError;
|
||||
private boolean enabled;
|
||||
private long netconfRevision;
|
||||
private InetSocketAddress[] assignedAddresses;
|
||||
private VirtualNetworkRoute[] routes;
|
||||
|
||||
private VirtualNetworkConfig() {
|
||||
|
||||
}
|
||||
|
||||
public boolean equals(VirtualNetworkConfig cfg) {
|
||||
boolean aaEqual = true;
|
||||
if(assignedAddresses.length == cfg.assignedAddresses.length) {
|
||||
for(int i = 0; i < assignedAddresses.length; ++i) {
|
||||
if(!assignedAddresses[i].equals(cfg.assignedAddresses[i])) {
|
||||
aaEqual = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
aaEqual = false;
|
||||
}
|
||||
|
||||
boolean routesEqual = true;
|
||||
if(routes.length == cfg.routes.length) {
|
||||
for (int i = 0; i < routes.length; ++i) {
|
||||
if (!routes[i].equals(cfg.routes[i])) {
|
||||
routesEqual = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
routesEqual = false;
|
||||
}
|
||||
|
||||
return nwid == cfg.nwid &&
|
||||
mac == cfg.mac &&
|
||||
name.equals(cfg.name) &&
|
||||
status.equals(cfg.status) &&
|
||||
type.equals(cfg.type) &&
|
||||
mtu == cfg.mtu &&
|
||||
dhcp == cfg.dhcp &&
|
||||
bridge == cfg.bridge &&
|
||||
broadcastEnabled == cfg.broadcastEnabled &&
|
||||
portError == cfg.portError &&
|
||||
enabled == cfg.enabled &&
|
||||
aaEqual && routesEqual;
|
||||
}
|
||||
|
||||
public int compareTo(VirtualNetworkConfig cfg) {
|
||||
if(cfg.nwid == this.nwid) {
|
||||
return 0;
|
||||
} else {
|
||||
return this.nwid > cfg.nwid ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 64-bit ZeroTier network ID
|
||||
*/
|
||||
public final long networkId() {
|
||||
return nwid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ethernet MAC (40 bits) that should be assigned to port
|
||||
*/
|
||||
public final long macAddress() {
|
||||
return mac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Network name (from network configuration master)
|
||||
*/
|
||||
public final String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Network configuration request status
|
||||
*/
|
||||
public final VirtualNetworkStatus networkStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Network type
|
||||
*/
|
||||
public final VirtualNetworkType networkType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum interface MTU
|
||||
*/
|
||||
public final int mtu() {
|
||||
return mtu;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the network this port belongs to indicates DHCP availability
|
||||
*
|
||||
* <p>This is a suggestion. The underlying implementation is free to ignore it
|
||||
* for security or other reasons. This is simply a netconf parameter that
|
||||
* means 'DHCP is available on this network.'</p>
|
||||
*/
|
||||
public final boolean isDhcpAvailable() {
|
||||
return dhcp;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this port is allowed to bridge to other networks
|
||||
*
|
||||
* <p>This is informational. If this is false, bridged packets will simply
|
||||
* be dropped and bridging won't work.</p>
|
||||
*/
|
||||
public final boolean isBridgeEnabled() {
|
||||
return bridge;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic
|
||||
*/
|
||||
public final boolean broadcastEnabled() {
|
||||
return broadcastEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the network is in PORT_ERROR state, this is the error most recently returned by the port config callback
|
||||
*/
|
||||
public final int portError() {
|
||||
return portError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Network config revision as reported by netconf master
|
||||
*
|
||||
* <p>If this is zero, it means we're still waiting for our netconf.</p>
|
||||
*/
|
||||
public final long netconfRevision() {
|
||||
return netconfRevision;
|
||||
}
|
||||
|
||||
/**
|
||||
* ZeroTier-assigned addresses (in {@link java.net.InetSocketAddress} objects)
|
||||
*
|
||||
* For IP, the port number of the sockaddr_XX structure contains the number
|
||||
* of bits in the address netmask. Only the IP address and port are used.
|
||||
* Other fields like interface number can be ignored.
|
||||
*
|
||||
* This is only used for ZeroTier-managed address assignments sent by the
|
||||
* virtual network's configuration master.
|
||||
*/
|
||||
public final InetSocketAddress[] assignedAddresses() {
|
||||
return assignedAddresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* ZeroTier-assigned routes (in {@link com.zerotier.sdk.VirtualNetworkRoute} objects)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public final VirtualNetworkRoute[] routes() { return routes; }
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
|
||||
public interface VirtualNetworkConfigListener {
|
||||
/**
|
||||
* Callback called to update virtual network port configuration
|
||||
*
|
||||
* <p>This can be called at any time to update the configuration of a virtual
|
||||
* network port. The parameter after the network ID specifies whether this
|
||||
* port is being brought up, updated, brought down, or permanently deleted.
|
||||
*
|
||||
* This in turn should be used by the underlying implementation to create
|
||||
* and configure tap devices at the OS (or virtual network stack) layer.</P>
|
||||
*
|
||||
* This should not call {@link Node#multicastSubscribe} or other network-modifying
|
||||
* methods, as this could cause a deadlock in multithreaded or interrupt
|
||||
* driven environments.
|
||||
*
|
||||
* This must return 0 on success. It can return any OS-dependent error code
|
||||
* on failure, and this results in the network being placed into the
|
||||
* PORT_ERROR state.
|
||||
*
|
||||
* @param nwid network id
|
||||
* @param op {@link VirtualNetworkConfigOperation} enum describing the configuration operation
|
||||
* @param config {@link VirtualNetworkConfig} object with the new configuration
|
||||
* @return 0 on success
|
||||
*/
|
||||
public int onNetworkConfigurationUpdated(
|
||||
long nwid,
|
||||
VirtualNetworkConfigOperation op,
|
||||
VirtualNetworkConfig config);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
package com.zerotier.sdk;
|
||||
|
||||
public enum VirtualNetworkConfigOperation {
|
||||
/**
|
||||
* Network is coming up (either for the first time or after service restart)
|
||||
*/
|
||||
VIRTUAL_NETWORK_CONFIG_OPERATION_UP,
|
||||
|
||||
/**
|
||||
* Network configuration has been updated
|
||||
*/
|
||||
VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE,
|
||||
|
||||
/**
|
||||
* Network is going down (not permanently)
|
||||
*/
|
||||
VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,
|
||||
|
||||
/**
|
||||
* Network is going down permanently (leave/delete)
|
||||
*/
|
||||
VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
public interface VirtualNetworkFrameListener {
|
||||
/**
|
||||
* Function to send a frame out to a virtual network port
|
||||
*
|
||||
* @param nwid ZeroTier One network ID
|
||||
* @param srcMac source MAC address
|
||||
* @param destMac destination MAC address
|
||||
* @param ethertype
|
||||
* @param vlanId
|
||||
* @param frameData data to send
|
||||
*/
|
||||
public void onVirtualNetworkFrame(
|
||||
long nwid,
|
||||
long srcMac,
|
||||
long destMac,
|
||||
long etherType,
|
||||
long vlanId,
|
||||
byte[] frameData);
|
||||
}
|
||||
102
zerotierone/java/src/com/zerotier/sdk/VirtualNetworkRoute.java
Normal file
102
zerotierone/java/src/com/zerotier/sdk/VirtualNetworkRoute.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
package com.zerotier.sdk;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public final class VirtualNetworkRoute implements Comparable<VirtualNetworkRoute>
|
||||
{
|
||||
private VirtualNetworkRoute() {
|
||||
target = null;
|
||||
via = null;
|
||||
flags = 0;
|
||||
metric = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default
|
||||
*/
|
||||
public InetSocketAddress target;
|
||||
|
||||
/**
|
||||
* Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway)
|
||||
*/
|
||||
public InetSocketAddress via;
|
||||
|
||||
/**
|
||||
* Route flags
|
||||
*/
|
||||
public int flags;
|
||||
|
||||
/**
|
||||
* Route metric (not currently used)
|
||||
*/
|
||||
public int metric;
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(VirtualNetworkRoute other) {
|
||||
return target.toString().compareTo(other.target.toString());
|
||||
}
|
||||
|
||||
public boolean equals(VirtualNetworkRoute other) {
|
||||
boolean targetEquals;
|
||||
if (target == null && other.target == null) {
|
||||
targetEquals = true;
|
||||
}
|
||||
else if (target == null && other.target != null) {
|
||||
targetEquals = false;
|
||||
}
|
||||
else if (target != null && other.target == null) {
|
||||
targetEquals = false;
|
||||
}
|
||||
else {
|
||||
targetEquals = target.equals(other.target);
|
||||
}
|
||||
|
||||
|
||||
boolean viaEquals;
|
||||
if (via == null && other.via == null) {
|
||||
viaEquals = true;
|
||||
}
|
||||
else if (via == null && other.via != null) {
|
||||
viaEquals = false;
|
||||
}
|
||||
else if (via != null && other.via == null) {
|
||||
viaEquals = false;
|
||||
}
|
||||
else {
|
||||
viaEquals = via.equals(other.via);
|
||||
}
|
||||
|
||||
return viaEquals &&
|
||||
viaEquals &&
|
||||
flags == other.flags &&
|
||||
metric == other.metric;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
package com.zerotier.sdk;
|
||||
|
||||
public enum VirtualNetworkStatus {
|
||||
/**
|
||||
* Waiting for network configuration (also means revision == 0)
|
||||
*/
|
||||
NETWORK_STATUS_REQUESTING_CONFIGURATION,
|
||||
|
||||
/**
|
||||
* Configuration received and we are authorized
|
||||
*/
|
||||
NETWORK_STATUS_OK,
|
||||
|
||||
/**
|
||||
* Netconf master told us 'nope'
|
||||
*/
|
||||
NETWORK_STATUS_ACCESS_DENIED,
|
||||
|
||||
/**
|
||||
* Netconf master exists, but this virtual network does not
|
||||
*/
|
||||
NETWORK_STATUS_NOT_FOUND,
|
||||
|
||||
/**
|
||||
* Initialization of network failed or other internal error
|
||||
*/
|
||||
NETWORK_STATUS_PORT_ERROR,
|
||||
|
||||
/**
|
||||
* ZeroTier One version too old
|
||||
*/
|
||||
NETWORK_STATUS_CLIENT_TOO_OLD
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
package com.zerotier.sdk;
|
||||
|
||||
public enum VirtualNetworkType {
|
||||
/**
|
||||
* Private networks are authorized via certificates of membership
|
||||
*/
|
||||
NETWORK_TYPE_PRIVATE,
|
||||
|
||||
/**
|
||||
* Public networks have no access control -- they'll always be AUTHORIZED
|
||||
*/
|
||||
NETWORK_TYPE_PUBLIC
|
||||
}
|
||||
84
zerotierone/make-bsd.mk
Normal file
84
zerotierone/make-bsd.mk
Normal file
@@ -0,0 +1,84 @@
|
||||
INCLUDES=
|
||||
DEFS=
|
||||
LIBS=
|
||||
|
||||
include objects.mk
|
||||
OBJS+=osdep/BSDEthernetTap.o ext/http-parser/http_parser.o
|
||||
|
||||
# Build with ZT_ENABLE_CLUSTER=1 to build with cluster support
|
||||
ifeq ($(ZT_ENABLE_CLUSTER),1)
|
||||
DEFS+=-DZT_ENABLE_CLUSTER
|
||||
endif
|
||||
|
||||
# "make debug" is a shortcut for this
|
||||
ifeq ($(ZT_DEBUG),1)
|
||||
DEFS+=-DZT_TRACE
|
||||
CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS)
|
||||
LDFLAGS+=
|
||||
STRIP=echo
|
||||
# The following line enables optimization for the crypto code, since
|
||||
# C25519 in particular is almost UNUSABLE in heavy testing without it.
|
||||
node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS)
|
||||
else
|
||||
CFLAGS?=-O3 -fstack-protector
|
||||
CFLAGS+=-Wall -fPIE -fvisibility=hidden -fstack-protector -pthread $(INCLUDES) -DNDEBUG $(DEFS)
|
||||
LDFLAGS+=-pie -Wl,-z,relro,-z,now
|
||||
STRIP=strip --strip-all
|
||||
endif
|
||||
|
||||
# Determine system build architecture from compiler target
|
||||
CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1)
|
||||
ZT_ARCHITECTURE=0
|
||||
ifeq ($(CC_MACH),x86_64)
|
||||
ZT_ARCHITECTURE=2
|
||||
endif
|
||||
ifeq ($(CC_MACH),amd64)
|
||||
ZT_ARCHITECTURE=2
|
||||
endif
|
||||
ifeq ($(CC_MACH),i386)
|
||||
ZT_ARCHITECTURE=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),i686)
|
||||
ZT_ARCHITECTURE=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),arm)
|
||||
ZT_ARCHITECTURE=3
|
||||
endif
|
||||
ifeq ($(CC_MACH),arm64)
|
||||
ZT_ARCHITECTURE=4
|
||||
endif
|
||||
ifeq ($(CC_MACH),aarch64)
|
||||
ZT_ARCHITECTURE=4
|
||||
endif
|
||||
DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\""
|
||||
|
||||
CXXFLAGS+=$(CFLAGS) -fno-rtti -std=c++11 -D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_MATH -D_GLIBCXX_USE_C99_MATH_TR1
|
||||
|
||||
all: one
|
||||
|
||||
one: $(OBJS) service/OneService.o one.o
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o $(LIBS)
|
||||
$(STRIP) zerotier-one
|
||||
ln -sf zerotier-one zerotier-idtool
|
||||
ln -sf zerotier-one zerotier-cli
|
||||
|
||||
selftest: $(OBJS) selftest.o
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS)
|
||||
$(STRIP) zerotier-selftest
|
||||
|
||||
clean:
|
||||
rm -rf *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o build-* zerotier-one zerotier-idtool zerotier-selftest zerotier-cli ZeroTierOneInstaller-*
|
||||
|
||||
debug: FORCE
|
||||
make -j 4 ZT_DEBUG=1
|
||||
|
||||
install: one
|
||||
rm -f /usr/local/sbin/zerotier-one
|
||||
cp zerotier-one /usr/local/sbin
|
||||
ln -sf /usr/local/sbin/zerotier-one /usr/local/sbin/zerotier-cli
|
||||
ln -sf /usr/local/sbin/zerotier-one /usr/local/bin/zerotier-idtool
|
||||
|
||||
uninstall: FORCE
|
||||
rm -rf /usr/local/sbin/zerotier-one /usr/local/sbin/zerotier-cli /usr/local/bin/zerotier-idtool /var/db/zerotier-one/zerotier-one.port /var/db/zerotier-one/zerotier-one.pid /var/db/zerotier-one/iddb.d
|
||||
|
||||
FORCE:
|
||||
65
zerotierone/node/Capability.cpp
Normal file
65
zerotierone/node/Capability.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Capability.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Switch.hpp"
|
||||
#include "Network.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
int Capability::verify(const RuntimeEnvironment *RR) const
|
||||
{
|
||||
try {
|
||||
// There must be at least one entry, and sanity check for bad chain max length
|
||||
if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH))
|
||||
return -1;
|
||||
|
||||
// Validate all entries in chain of custody
|
||||
Buffer<(sizeof(Capability) * 2)> tmp;
|
||||
this->serialize(tmp,true);
|
||||
for(unsigned int c=0;c<_maxCustodyChainLength;++c) {
|
||||
if (c == 0) {
|
||||
if ((!_custody[c].to)||(!_custody[c].from)||(_custody[c].from != Network::controllerFor(_nwid)))
|
||||
return -1; // the first entry must be present and from the network's controller
|
||||
} else {
|
||||
if (!_custody[c].to)
|
||||
return 0; // all previous entries were valid, so we are valid
|
||||
else if ((!_custody[c].from)||(_custody[c].from != _custody[c-1].to))
|
||||
return -1; // otherwise if we have another entry it must be from the previous holder in the chain
|
||||
}
|
||||
|
||||
const Identity id(RR->topology->getIdentity(_custody[c].from));
|
||||
if (id) {
|
||||
if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature))
|
||||
return -1;
|
||||
} else {
|
||||
RR->sw->requestWhois(_custody[c].from);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// We reached max custody chain length and everything was valid
|
||||
return 0;
|
||||
} catch ( ... ) {}
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
464
zerotierone/node/Capability.hpp
Normal file
464
zerotierone/node/Capability.hpp
Normal file
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_CAPABILITY_HPP
|
||||
#define ZT_CAPABILITY_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "C25519.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "../include/ZeroTierOne.h"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
|
||||
/**
|
||||
* A set of grouped and signed network flow rules
|
||||
*
|
||||
* On the sending side the sender does the following for each packet:
|
||||
*
|
||||
* (1) Evaluates its capabilities in ascending order of ID to determine
|
||||
* which capability allows it to transmit this packet.
|
||||
* (2) If it has not done so lately, it then sends this capability to the
|
||||
* receving peer ("presents" it).
|
||||
* (3) The sender then sends the packet.
|
||||
*
|
||||
* On the receiving side the receiver evaluates the capabilities presented
|
||||
* by the sender. If any valid un-expired capability allows this packet it
|
||||
* is accepted.
|
||||
*
|
||||
* Note that this is after evaluation of network scope rules and only if
|
||||
* network scope rules do not deliver an explicit match.
|
||||
*/
|
||||
class Capability
|
||||
{
|
||||
public:
|
||||
Capability()
|
||||
{
|
||||
memset(this,0,sizeof(Capability));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id Capability ID
|
||||
* @param nwid Network ID
|
||||
* @param ts Timestamp (at controller)
|
||||
* @param mccl Maximum custody chain length (1 to create non-transferrable capability)
|
||||
* @param rules Network flow rules for this capability
|
||||
* @param ruleCount Number of flow rules
|
||||
*/
|
||||
Capability(uint32_t id,uint64_t nwid,uint64_t ts,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
|
||||
{
|
||||
memset(this,0,sizeof(Capability));
|
||||
_nwid = nwid;
|
||||
_ts = ts;
|
||||
_id = id;
|
||||
_maxCustodyChainLength = (mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1;
|
||||
_ruleCount = (ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES;
|
||||
if (_ruleCount)
|
||||
memcpy(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Rules -- see ruleCount() for size of array
|
||||
*/
|
||||
inline const ZT_VirtualNetworkRule *rules() const { return _rules; }
|
||||
|
||||
/**
|
||||
* @return Number of rules in rules()
|
||||
*/
|
||||
inline unsigned int ruleCount() const { return _ruleCount; }
|
||||
|
||||
/**
|
||||
* @return ID and evaluation order of this capability in network
|
||||
*/
|
||||
inline uint32_t id() const { return _id; }
|
||||
|
||||
/**
|
||||
* @return Network ID for which this capability was issued
|
||||
*/
|
||||
inline uint64_t networkId() const { return _nwid; }
|
||||
|
||||
/**
|
||||
* @return Timestamp
|
||||
*/
|
||||
inline uint64_t timestamp() const { return _ts; }
|
||||
|
||||
/**
|
||||
* @return Last 'to' address in chain of custody
|
||||
*/
|
||||
inline Address issuedTo() const
|
||||
{
|
||||
Address i2;
|
||||
for(unsigned int i=0;i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH;++i) {
|
||||
if (!_custody[i].to)
|
||||
return i2;
|
||||
else i2 = _custody[i].to;
|
||||
}
|
||||
return i2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign this capability and add signature to its chain of custody
|
||||
*
|
||||
* If this returns false, this object should be considered to be
|
||||
* in an undefined state and should be discarded. False can be returned
|
||||
* if there is no more room for signatures (max chain length reached)
|
||||
* or if the 'from' identity does not include a secret key to allow
|
||||
* it to sign anything.
|
||||
*
|
||||
* @param from Signing identity (must have secret)
|
||||
* @param to Recipient of this signature
|
||||
* @return True if signature successful and chain of custody appended
|
||||
*/
|
||||
inline bool sign(const Identity &from,const Address &to)
|
||||
{
|
||||
try {
|
||||
for(unsigned int i=0;((i<_maxCustodyChainLength)&&(i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH));++i) {
|
||||
if (!(_custody[i].to)) {
|
||||
Buffer<(sizeof(Capability) * 2)> tmp;
|
||||
this->serialize(tmp,true);
|
||||
_custody[i].to = to;
|
||||
_custody[i].from = from.address();
|
||||
_custody[i].signature = from.sign(tmp.data(),tmp.size());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify this capability's chain of custody and signatures
|
||||
*
|
||||
* @param RR Runtime environment to provide for peer lookup, etc.
|
||||
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain
|
||||
*/
|
||||
int verify(const RuntimeEnvironment *RR) const;
|
||||
|
||||
template<unsigned int C>
|
||||
static inline void serializeRules(Buffer<C> &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
|
||||
{
|
||||
for(unsigned int i=0;i<ruleCount;++i) {
|
||||
// Each rule consists of its 8-bit type followed by the size of that type's
|
||||
// field followed by field data. The inclusion of the size will allow non-supported
|
||||
// rules to be ignored but still parsed.
|
||||
b.append((uint8_t)rules[i].t);
|
||||
switch((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3f)) {
|
||||
default:
|
||||
b.append((uint8_t)0);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_ACTION_TEE:
|
||||
case ZT_NETWORK_RULE_ACTION_WATCH:
|
||||
case ZT_NETWORK_RULE_ACTION_REDIRECT:
|
||||
b.append((uint8_t)14);
|
||||
b.append((uint64_t)rules[i].v.fwd.address);
|
||||
b.append((uint32_t)rules[i].v.fwd.flags);
|
||||
b.append((uint16_t)rules[i].v.fwd.length); // unused for redirect
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
|
||||
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
|
||||
b.append((uint8_t)5);
|
||||
Address(rules[i].v.zt).appendTo(b);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_VLAN_ID:
|
||||
b.append((uint8_t)2);
|
||||
b.append((uint16_t)rules[i].v.vlanId);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_VLAN_PCP:
|
||||
b.append((uint8_t)1);
|
||||
b.append((uint8_t)rules[i].v.vlanPcp);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_VLAN_DEI:
|
||||
b.append((uint8_t)1);
|
||||
b.append((uint8_t)rules[i].v.vlanDei);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
|
||||
case ZT_NETWORK_RULE_MATCH_MAC_DEST:
|
||||
b.append((uint8_t)6);
|
||||
b.append(rules[i].v.mac,6);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
|
||||
case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
|
||||
b.append((uint8_t)5);
|
||||
b.append(&(rules[i].v.ipv4.ip),4);
|
||||
b.append((uint8_t)rules[i].v.ipv4.mask);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
|
||||
case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
|
||||
b.append((uint8_t)17);
|
||||
b.append(rules[i].v.ipv6.ip,16);
|
||||
b.append((uint8_t)rules[i].v.ipv6.mask);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IP_TOS:
|
||||
b.append((uint8_t)3);
|
||||
b.append((uint8_t)rules[i].v.ipTos.mask);
|
||||
b.append((uint8_t)rules[i].v.ipTos.value[0]);
|
||||
b.append((uint8_t)rules[i].v.ipTos.value[1]);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
|
||||
b.append((uint8_t)1);
|
||||
b.append((uint8_t)rules[i].v.ipProtocol);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
|
||||
b.append((uint8_t)2);
|
||||
b.append((uint16_t)rules[i].v.etherType);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_ICMP:
|
||||
b.append((uint8_t)3);
|
||||
b.append((uint8_t)rules[i].v.icmp.type);
|
||||
b.append((uint8_t)rules[i].v.icmp.code);
|
||||
b.append((uint8_t)rules[i].v.icmp.flags);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
|
||||
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
|
||||
b.append((uint8_t)4);
|
||||
b.append((uint16_t)rules[i].v.port[0]);
|
||||
b.append((uint16_t)rules[i].v.port[1]);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS:
|
||||
b.append((uint8_t)8);
|
||||
b.append((uint64_t)rules[i].v.characteristics);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE:
|
||||
b.append((uint8_t)4);
|
||||
b.append((uint16_t)rules[i].v.frameSize[0]);
|
||||
b.append((uint16_t)rules[i].v.frameSize[1]);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_RANDOM:
|
||||
b.append((uint8_t)4);
|
||||
b.append((uint32_t)rules[i].v.randomProbability);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE:
|
||||
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND:
|
||||
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR:
|
||||
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR:
|
||||
case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL:
|
||||
case ZT_NETWORK_RULE_MATCH_TAG_SENDER:
|
||||
case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER:
|
||||
b.append((uint8_t)8);
|
||||
b.append((uint32_t)rules[i].v.tag.id);
|
||||
b.append((uint32_t)rules[i].v.tag.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
static inline void deserializeRules(const Buffer<C> &b,unsigned int &p,ZT_VirtualNetworkRule *rules,unsigned int &ruleCount,const unsigned int maxRuleCount)
|
||||
{
|
||||
while ((ruleCount < maxRuleCount)&&(p < b.size())) {
|
||||
rules[ruleCount].t = (uint8_t)b[p++];
|
||||
const unsigned int fieldLen = (unsigned int)b[p++];
|
||||
switch((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) {
|
||||
default:
|
||||
break;
|
||||
case ZT_NETWORK_RULE_ACTION_TEE:
|
||||
case ZT_NETWORK_RULE_ACTION_WATCH:
|
||||
case ZT_NETWORK_RULE_ACTION_REDIRECT:
|
||||
rules[ruleCount].v.fwd.address = b.template at<uint64_t>(p);
|
||||
rules[ruleCount].v.fwd.flags = b.template at<uint32_t>(p + 8);
|
||||
rules[ruleCount].v.fwd.length = b.template at<uint16_t>(p + 12);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
|
||||
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
|
||||
rules[ruleCount].v.zt = Address(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt();
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_VLAN_ID:
|
||||
rules[ruleCount].v.vlanId = b.template at<uint16_t>(p);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_VLAN_PCP:
|
||||
rules[ruleCount].v.vlanPcp = (uint8_t)b[p];
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_VLAN_DEI:
|
||||
rules[ruleCount].v.vlanDei = (uint8_t)b[p];
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
|
||||
case ZT_NETWORK_RULE_MATCH_MAC_DEST:
|
||||
memcpy(rules[ruleCount].v.mac,b.field(p,6),6);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
|
||||
case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
|
||||
memcpy(&(rules[ruleCount].v.ipv4.ip),b.field(p,4),4);
|
||||
rules[ruleCount].v.ipv4.mask = (uint8_t)b[p + 4];
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
|
||||
case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
|
||||
memcpy(rules[ruleCount].v.ipv6.ip,b.field(p,16),16);
|
||||
rules[ruleCount].v.ipv6.mask = (uint8_t)b[p + 16];
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IP_TOS:
|
||||
rules[ruleCount].v.ipTos.mask = (uint8_t)b[p];
|
||||
rules[ruleCount].v.ipTos.value[0] = (uint8_t)b[p+1];
|
||||
rules[ruleCount].v.ipTos.value[1] = (uint8_t)b[p+2];
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
|
||||
rules[ruleCount].v.ipProtocol = (uint8_t)b[p];
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
|
||||
rules[ruleCount].v.etherType = b.template at<uint16_t>(p);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_ICMP:
|
||||
rules[ruleCount].v.icmp.type = (uint8_t)b[p];
|
||||
rules[ruleCount].v.icmp.code = (uint8_t)b[p+1];
|
||||
rules[ruleCount].v.icmp.flags = (uint8_t)b[p+2];
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
|
||||
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
|
||||
rules[ruleCount].v.port[0] = b.template at<uint16_t>(p);
|
||||
rules[ruleCount].v.port[1] = b.template at<uint16_t>(p + 2);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS:
|
||||
rules[ruleCount].v.characteristics = b.template at<uint64_t>(p);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE:
|
||||
rules[ruleCount].v.frameSize[0] = b.template at<uint16_t>(p);
|
||||
rules[ruleCount].v.frameSize[1] = b.template at<uint16_t>(p + 2);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_RANDOM:
|
||||
rules[ruleCount].v.randomProbability = b.template at<uint32_t>(p);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE:
|
||||
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND:
|
||||
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR:
|
||||
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR:
|
||||
case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL:
|
||||
case ZT_NETWORK_RULE_MATCH_TAG_SENDER:
|
||||
case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER:
|
||||
rules[ruleCount].v.tag.id = b.template at<uint32_t>(p);
|
||||
rules[ruleCount].v.tag.value = b.template at<uint32_t>(p + 4);
|
||||
break;
|
||||
}
|
||||
p += fieldLen;
|
||||
++ruleCount;
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
inline void serialize(Buffer<C> &b,const bool forSign = false) const
|
||||
{
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
|
||||
// These are the same between Tag and Capability
|
||||
b.append(_nwid);
|
||||
b.append(_ts);
|
||||
b.append(_id);
|
||||
|
||||
b.append((uint16_t)_ruleCount);
|
||||
serializeRules(b,_rules,_ruleCount);
|
||||
b.append((uint8_t)_maxCustodyChainLength);
|
||||
|
||||
if (!forSign) {
|
||||
for(unsigned int i=0;;++i) {
|
||||
if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) {
|
||||
_custody[i].to.appendTo(b);
|
||||
_custody[i].from.appendTo(b);
|
||||
b.append((uint8_t)1); // 1 == Ed25519 signature
|
||||
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
|
||||
b.append(_custody[i].signature.data,ZT_C25519_SIGNATURE_LEN);
|
||||
} else {
|
||||
b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is the size of any additional fields, currently 0.
|
||||
b.append((uint16_t)0);
|
||||
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
|
||||
{
|
||||
memset(this,0,sizeof(Capability));
|
||||
|
||||
unsigned int p = startAt;
|
||||
|
||||
_nwid = b.template at<uint64_t>(p); p += 8;
|
||||
_ts = b.template at<uint64_t>(p); p += 8;
|
||||
_id = b.template at<uint32_t>(p); p += 4;
|
||||
|
||||
const unsigned int rc = b.template at<uint16_t>(p); p += 2;
|
||||
if (rc > ZT_MAX_CAPABILITY_RULES)
|
||||
throw std::runtime_error("rule overflow");
|
||||
deserializeRules(b,p,_rules,_ruleCount,rc);
|
||||
|
||||
_maxCustodyChainLength = (unsigned int)b[p++];
|
||||
if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH))
|
||||
throw std::runtime_error("invalid max custody chain length");
|
||||
|
||||
for(unsigned int i=0;;++i) {
|
||||
const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||
if (!to)
|
||||
break;
|
||||
if ((i >= _maxCustodyChainLength)||(i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH))
|
||||
throw std::runtime_error("unterminated custody chain");
|
||||
_custody[i].to = to;
|
||||
_custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||
if (b[p++] == 1) {
|
||||
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
|
||||
throw std::runtime_error("invalid signature");
|
||||
p += 2;
|
||||
memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
|
||||
} else {
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
}
|
||||
}
|
||||
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
if (p > b.size())
|
||||
throw std::runtime_error("extended field overflow");
|
||||
|
||||
return (p - startAt);
|
||||
}
|
||||
|
||||
// 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 (memcmp(this,&c,sizeof(Capability)) == 0); }
|
||||
inline bool operator!=(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) != 0); }
|
||||
|
||||
private:
|
||||
uint64_t _nwid;
|
||||
uint64_t _ts;
|
||||
uint32_t _id;
|
||||
|
||||
unsigned int _maxCustodyChainLength;
|
||||
|
||||
unsigned int _ruleCount;
|
||||
ZT_VirtualNetworkRule _rules[ZT_MAX_CAPABILITY_RULES];
|
||||
|
||||
struct {
|
||||
Address to;
|
||||
Address from;
|
||||
C25519::Signature signature;
|
||||
} _custody[ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH];
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
63
zerotierone/node/CertificateOfOwnership.cpp
Normal file
63
zerotierone/node/CertificateOfOwnership.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CertificateOfOwnership.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Switch.hpp"
|
||||
#include "Network.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
int CertificateOfOwnership::verify(const RuntimeEnvironment *RR) const
|
||||
{
|
||||
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
|
||||
return -1;
|
||||
const Identity id(RR->topology->getIdentity(_signedBy));
|
||||
if (!id) {
|
||||
RR->sw->requestWhois(_signedBy);
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp;
|
||||
this->serialize(tmp,true);
|
||||
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
|
||||
} catch ( ... ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing &t,const void *v,unsigned int l) const
|
||||
{
|
||||
for(unsigned int i=0,j=_thingCount;i<j;++i) {
|
||||
if (_thingTypes[i] == (uint8_t)t) {
|
||||
unsigned int k = 0;
|
||||
while (k < l) {
|
||||
if (reinterpret_cast<const uint8_t *>(v)[k] != _thingValues[i][k])
|
||||
break;
|
||||
++k;
|
||||
}
|
||||
if (k == l)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
236
zerotierone/node/CertificateOfOwnership.hpp
Normal file
236
zerotierone/node/CertificateOfOwnership.hpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP
|
||||
#define ZT_CERTIFICATEOFOWNERSHIP_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "C25519.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
#include "MAC.hpp"
|
||||
|
||||
// Max things per CertificateOfOwnership
|
||||
#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS 16
|
||||
|
||||
// Maximum size of a thing's value field in bytes
|
||||
#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE 16
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
|
||||
/**
|
||||
* Certificate indicating ownership of a network identifier
|
||||
*/
|
||||
class CertificateOfOwnership
|
||||
{
|
||||
public:
|
||||
enum Thing
|
||||
{
|
||||
THING_NULL = 0,
|
||||
THING_MAC_ADDRESS = 1,
|
||||
THING_IPV4_ADDRESS = 2,
|
||||
THING_IPV6_ADDRESS = 3
|
||||
};
|
||||
|
||||
CertificateOfOwnership() :
|
||||
_networkId(0),
|
||||
_ts(0),
|
||||
_id(0),
|
||||
_thingCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
CertificateOfOwnership(const uint64_t nwid,const uint64_t ts,const Address &issuedTo,const uint32_t id) :
|
||||
_networkId(nwid),
|
||||
_ts(ts),
|
||||
_flags(0),
|
||||
_id(id),
|
||||
_thingCount(0),
|
||||
_issuedTo(issuedTo)
|
||||
{
|
||||
}
|
||||
|
||||
inline uint64_t networkId() const { return _networkId; }
|
||||
inline uint64_t timestamp() const { return _ts; }
|
||||
inline uint32_t id() const { return _id; }
|
||||
inline unsigned int thingCount() const { return (unsigned int)_thingCount; }
|
||||
|
||||
inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; }
|
||||
inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; }
|
||||
|
||||
inline const Address &issuedTo() const { return _issuedTo; }
|
||||
|
||||
inline bool owns(const InetAddress &ip) const
|
||||
{
|
||||
if (ip.ss_family == AF_INET)
|
||||
return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
|
||||
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 false;
|
||||
}
|
||||
|
||||
inline bool owns(const MAC &mac) const
|
||||
{
|
||||
uint8_t tmp[6];
|
||||
mac.copyTo(tmp,6);
|
||||
return this->_owns(THING_MAC_ADDRESS,tmp,6);
|
||||
}
|
||||
|
||||
inline void addThing(const InetAddress &ip)
|
||||
{
|
||||
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
|
||||
if (ip.ss_family == AF_INET) {
|
||||
_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
|
||||
memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
|
||||
++_thingCount;
|
||||
} else if (ip.ss_family == AF_INET6) {
|
||||
_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
|
||||
memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
|
||||
++_thingCount;
|
||||
}
|
||||
}
|
||||
|
||||
inline void addThing(const MAC &mac)
|
||||
{
|
||||
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
|
||||
_thingTypes[_thingCount] = THING_MAC_ADDRESS;
|
||||
mac.copyTo(_thingValues[_thingCount],6);
|
||||
++_thingCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param signer Signing identity, must have private key
|
||||
* @return True if signature was successful
|
||||
*/
|
||||
inline bool sign(const Identity &signer)
|
||||
{
|
||||
if (signer.hasPrivate()) {
|
||||
Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
|
||||
_signedBy = signer.address();
|
||||
this->serialize(tmp,true);
|
||||
_signature = signer.sign(tmp.data(),tmp.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RR Runtime environment to allow identity lookup for signedBy
|
||||
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature
|
||||
*/
|
||||
int verify(const RuntimeEnvironment *RR) const;
|
||||
|
||||
template<unsigned int C>
|
||||
inline void serialize(Buffer<C> &b,const bool forSign = false) const
|
||||
{
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
|
||||
b.append(_networkId);
|
||||
b.append(_ts);
|
||||
b.append(_flags);
|
||||
b.append(_id);
|
||||
b.append((uint16_t)_thingCount);
|
||||
for(unsigned int i=0,j=_thingCount;i<j;++i) {
|
||||
b.append((uint8_t)_thingTypes[i]);
|
||||
b.append(_thingValues[i],ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
|
||||
}
|
||||
|
||||
_issuedTo.appendTo(b);
|
||||
_signedBy.appendTo(b);
|
||||
if (!forSign) {
|
||||
b.append((uint8_t)1); // 1 == Ed25519
|
||||
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
|
||||
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
|
||||
}
|
||||
|
||||
b.append((uint16_t)0); // length of additional fields, currently 0
|
||||
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
|
||||
{
|
||||
unsigned int p = startAt;
|
||||
|
||||
memset(this,0,sizeof(CertificateOfOwnership));
|
||||
|
||||
_networkId = b.template at<uint64_t>(p); p += 8;
|
||||
_ts = b.template at<uint64_t>(p); p += 8;
|
||||
_flags = b.template at<uint64_t>(p); p += 8;
|
||||
_id = b.template at<uint32_t>(p); p += 4;
|
||||
_thingCount = b.template at<uint16_t>(p); p += 2;
|
||||
for(unsigned int i=0,j=_thingCount;i<j;++i) {
|
||||
if (i < ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
|
||||
_thingTypes[i] = (uint8_t)b[p++];
|
||||
memcpy(_thingValues[i],b.field(p,ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE),ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
|
||||
p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||
if (b[p++] == 1) {
|
||||
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
|
||||
throw std::runtime_error("invalid signature length");
|
||||
p += 2;
|
||||
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
|
||||
} else {
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
}
|
||||
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
if (p > b.size())
|
||||
throw std::runtime_error("extended field overflow");
|
||||
|
||||
return (p - startAt);
|
||||
}
|
||||
|
||||
// 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 (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); }
|
||||
inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); }
|
||||
|
||||
private:
|
||||
bool _owns(const Thing &t,const void *v,unsigned int l) const;
|
||||
|
||||
uint64_t _networkId;
|
||||
uint64_t _ts;
|
||||
uint64_t _flags;
|
||||
uint32_t _id;
|
||||
uint16_t _thingCount;
|
||||
uint8_t _thingTypes[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS];
|
||||
uint8_t _thingValues[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS][ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE];
|
||||
Address _issuedTo;
|
||||
Address _signedBy;
|
||||
C25519::Signature _signature;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
161
zerotierone/node/CertificateOfRepresentation.hpp
Normal file
161
zerotierone/node/CertificateOfRepresentation.hpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_CERTIFICATEOFREPRESENTATION_HPP
|
||||
#define ZT_CERTIFICATEOFREPRESENTATION_HPP
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "C25519.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "Buffer.hpp"
|
||||
|
||||
/**
|
||||
* Maximum number of addresses allowed in a COR
|
||||
*/
|
||||
#define ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES ZT_MAX_UPSTREAMS
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class CertificateOfRepresentation
|
||||
{
|
||||
public:
|
||||
CertificateOfRepresentation()
|
||||
{
|
||||
memset(this,0,sizeof(CertificateOfRepresentation));
|
||||
}
|
||||
|
||||
inline uint64_t timestamp() const { return _timestamp; }
|
||||
inline const Address &representative(const unsigned int i) const { return _reps[i]; }
|
||||
inline unsigned int repCount() const { return _repCount; }
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
memset(this,0,sizeof(CertificateOfRepresentation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a representative if space remains
|
||||
*
|
||||
* @param r Representative to add
|
||||
* @return True if representative was added
|
||||
*/
|
||||
inline bool addRepresentative(const Address &r)
|
||||
{
|
||||
if (_repCount < ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) {
|
||||
_reps[_repCount++] = r;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign this COR with my identity
|
||||
*
|
||||
* @param myIdentity This node's identity
|
||||
* @param ts COR timestamp for establishing new vs. old
|
||||
*/
|
||||
inline void sign(const Identity &myIdentity,const uint64_t ts)
|
||||
{
|
||||
_timestamp = ts;
|
||||
Buffer<sizeof(CertificateOfRepresentation) + 32> tmp;
|
||||
this->serialize(tmp,true);
|
||||
_signature = myIdentity.sign(tmp.data(),tmp.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify this COR's signature
|
||||
*
|
||||
* @param senderIdentity Identity of sender of COR
|
||||
* @return True if COR is valid
|
||||
*/
|
||||
inline bool verify(const Identity &senderIdentity)
|
||||
{
|
||||
try {
|
||||
Buffer<sizeof(CertificateOfRepresentation) + 32> tmp;
|
||||
this->serialize(tmp,true);
|
||||
return senderIdentity.verify(tmp.data(),tmp.size(),_signature.data,ZT_C25519_SIGNATURE_LEN);
|
||||
} catch ( ... ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
inline void serialize(Buffer<C> &b,const bool forSign = false) const
|
||||
{
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
|
||||
b.append((uint64_t)_timestamp);
|
||||
b.append((uint16_t)_repCount);
|
||||
for(unsigned int i=0;i<_repCount;++i)
|
||||
_reps[i].appendTo(b);
|
||||
|
||||
if (!forSign) {
|
||||
b.append((uint8_t)1); // 1 == Ed25519 signature
|
||||
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN);
|
||||
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
|
||||
}
|
||||
|
||||
b.append((uint16_t)0); // size of any additional fields, currently 0
|
||||
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
|
||||
{
|
||||
clear();
|
||||
|
||||
unsigned int p = startAt;
|
||||
|
||||
_timestamp = b.template at<uint64_t>(p); p += 8;
|
||||
const unsigned int rc = b.template at<uint16_t>(p); p += 2;
|
||||
for(unsigned int i=0;i<rc;++i) {
|
||||
if (i < ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES)
|
||||
_reps[i].setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
|
||||
p += ZT_ADDRESS_LENGTH;
|
||||
}
|
||||
_repCount = (rc > ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES) ? ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES : rc;
|
||||
|
||||
if (b[p++] == 1) {
|
||||
if (b.template at<uint16_t>(p) == ZT_C25519_SIGNATURE_LEN) {
|
||||
p += 2;
|
||||
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
|
||||
p += ZT_C25519_SIGNATURE_LEN;
|
||||
} else throw std::runtime_error("invalid signature");
|
||||
} else {
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
}
|
||||
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
if (p > b.size())
|
||||
throw std::runtime_error("extended field overflow");
|
||||
|
||||
return (p - startAt);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t _timestamp;
|
||||
Address _reps[ZT_CERTIFICATEOFREPRESENTATION_MAX_ADDRESSES];
|
||||
unsigned int _repCount;
|
||||
C25519::Signature _signature;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
396
zerotierone/node/Membership.cpp
Normal file
396
zerotierone/node/Membership.cpp
Normal file
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Membership.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Peer.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Switch.hpp"
|
||||
#include "Packet.hpp"
|
||||
#include "Node.hpp"
|
||||
|
||||
#define ZT_CREDENTIAL_PUSH_EVERY (ZT_NETWORK_AUTOCONF_DELAY / 3)
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
Membership::Membership() :
|
||||
_lastUpdatedMulticast(0),
|
||||
_lastPushedCom(0),
|
||||
_comRevocationThreshold(0)
|
||||
{
|
||||
for(unsigned int i=0;i<ZT_MAX_NETWORK_TAGS;++i) _remoteTags[i] = &(_tagMem[i]);
|
||||
for(unsigned int i=0;i<ZT_MAX_NETWORK_CAPABILITIES;++i) _remoteCaps[i] = &(_capMem[i]);
|
||||
for(unsigned int i=0;i<ZT_MAX_CERTIFICATES_OF_OWNERSHIP;++i) _remoteCoos[i] = &(_cooMem[i]);
|
||||
}
|
||||
|
||||
void Membership::pushCredentials(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force)
|
||||
{
|
||||
bool sendCom = ( (nconf.com) && ( ((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) );
|
||||
|
||||
const Capability *sendCap;
|
||||
if (localCapabilityIndex >= 0) {
|
||||
sendCap = &(nconf.capabilities[localCapabilityIndex]);
|
||||
if ( (_localCaps[localCapabilityIndex].id != sendCap->id()) || ((now - _localCaps[localCapabilityIndex].lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
|
||||
_localCaps[localCapabilityIndex].lastPushed = now;
|
||||
_localCaps[localCapabilityIndex].id = sendCap->id();
|
||||
} else sendCap = (const Capability *)0;
|
||||
} else sendCap = (const Capability *)0;
|
||||
|
||||
const Tag *sendTags[ZT_MAX_NETWORK_TAGS];
|
||||
unsigned int sendTagCount = 0;
|
||||
for(unsigned int t=0;t<nconf.tagCount;++t) {
|
||||
if ( (_localTags[t].id != nconf.tags[t].id()) || ((now - _localTags[t].lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
|
||||
_localTags[t].lastPushed = now;
|
||||
_localTags[t].id = nconf.tags[t].id();
|
||||
sendTags[sendTagCount++] = &(nconf.tags[t]);
|
||||
}
|
||||
}
|
||||
|
||||
const CertificateOfOwnership *sendCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
|
||||
unsigned int sendCooCount = 0;
|
||||
for(unsigned int c=0;c<nconf.certificateOfOwnershipCount;++c) {
|
||||
if ( (_localCoos[c].id != nconf.certificatesOfOwnership[c].id()) || ((now - _localCoos[c].lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
|
||||
_localCoos[c].lastPushed = now;
|
||||
_localCoos[c].id = nconf.certificatesOfOwnership[c].id();
|
||||
sendCoos[sendCooCount++] = &(nconf.certificatesOfOwnership[c]);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int tagPtr = 0;
|
||||
unsigned int cooPtr = 0;
|
||||
while ((tagPtr < sendTagCount)||(cooPtr < sendCooCount)||(sendCom)||(sendCap)) {
|
||||
Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
|
||||
|
||||
if (sendCom) {
|
||||
sendCom = false;
|
||||
nconf.com.serialize(outp);
|
||||
_lastPushedCom = now;
|
||||
}
|
||||
outp.append((uint8_t)0x00);
|
||||
|
||||
if (sendCap) {
|
||||
outp.append((uint16_t)1);
|
||||
sendCap->serialize(outp);
|
||||
sendCap = (const Capability *)0;
|
||||
} else outp.append((uint16_t)0);
|
||||
|
||||
const unsigned int tagCountAt = outp.size();
|
||||
outp.addSize(2);
|
||||
unsigned int thisPacketTagCount = 0;
|
||||
while ((tagPtr < sendTagCount)&&((outp.size() + sizeof(Tag) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
|
||||
sendTags[tagPtr++]->serialize(outp);
|
||||
++thisPacketTagCount;
|
||||
}
|
||||
outp.setAt(tagCountAt,(uint16_t)thisPacketTagCount);
|
||||
|
||||
// No revocations, these propagate differently
|
||||
outp.append((uint16_t)0);
|
||||
|
||||
const unsigned int cooCountAt = outp.size();
|
||||
outp.addSize(2);
|
||||
unsigned int thisPacketCooCount = 0;
|
||||
while ((cooPtr < sendCooCount)&&((outp.size() + sizeof(CertificateOfOwnership) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
|
||||
sendCoos[cooPtr++]->serialize(outp);
|
||||
++thisPacketCooCount;
|
||||
}
|
||||
outp.setAt(cooCountAt,(uint16_t)thisPacketCooCount);
|
||||
|
||||
outp.compress();
|
||||
RR->sw->send(outp,true);
|
||||
}
|
||||
}
|
||||
|
||||
const Tag *Membership::getTag(const NetworkConfig &nconf,const uint32_t id) const
|
||||
{
|
||||
const _RemoteCredential<Tag> *const *t = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)id,_RemoteCredentialComp<Tag>());
|
||||
return ( ((t != &(_remoteTags[ZT_MAX_NETWORK_CAPABILITIES]))&&((*t)->id == (uint64_t)id)) ? ((((*t)->lastReceived)&&(_isCredentialTimestampValid(nconf,**t))) ? &((*t)->credential) : (const Tag *)0) : (const Tag *)0);
|
||||
}
|
||||
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfMembership &com)
|
||||
{
|
||||
const uint64_t newts = com.timestamp().first;
|
||||
if (newts <= _comRevocationThreshold) {
|
||||
TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (revoked)",com.issuedTo().toString().c_str(),com.networkId());
|
||||
return ADD_REJECTED;
|
||||
}
|
||||
|
||||
const uint64_t oldts = _com.timestamp().first;
|
||||
if (newts < oldts) {
|
||||
TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (older than current)",com.issuedTo().toString().c_str(),com.networkId());
|
||||
return ADD_REJECTED;
|
||||
}
|
||||
if ((newts == oldts)&&(_com == com)) {
|
||||
TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (redundant)",com.issuedTo().toString().c_str(),com.networkId());
|
||||
return ADD_ACCEPTED_REDUNDANT;
|
||||
}
|
||||
|
||||
switch(com.verify(RR)) {
|
||||
default:
|
||||
TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (invalid signature or object)",com.issuedTo().toString().c_str(),com.networkId());
|
||||
return ADD_REJECTED;
|
||||
case 0:
|
||||
TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (new)",com.issuedTo().toString().c_str(),com.networkId());
|
||||
_com = com;
|
||||
return ADD_ACCEPTED_NEW;
|
||||
case 1:
|
||||
return ADD_DEFERRED_FOR_WHOIS;
|
||||
}
|
||||
}
|
||||
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Tag &tag)
|
||||
{
|
||||
_RemoteCredential<Tag> *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)tag.id(),_RemoteCredentialComp<Tag>());
|
||||
_RemoteCredential<Tag> *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)tag.id())) ? *htmp : (_RemoteCredential<Tag> *)0;
|
||||
if (have) {
|
||||
if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > tag.timestamp()) ) {
|
||||
TRACE("addCredential(Tag) for %s on %.16llx REJECTED (revoked or too old)",tag.issuedTo().toString().c_str(),tag.networkId());
|
||||
return ADD_REJECTED;
|
||||
}
|
||||
if (have->credential == tag) {
|
||||
TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (redundant)",tag.issuedTo().toString().c_str(),tag.networkId());
|
||||
return ADD_ACCEPTED_REDUNDANT;
|
||||
}
|
||||
}
|
||||
|
||||
switch(tag.verify(RR)) {
|
||||
default:
|
||||
TRACE("addCredential(Tag) for %s on %.16llx REJECTED (invalid)",tag.issuedTo().toString().c_str(),tag.networkId());
|
||||
return ADD_REJECTED;
|
||||
case 0:
|
||||
TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId());
|
||||
if (!have) have = _newTag(tag.id());
|
||||
have->lastReceived = RR->node->now();
|
||||
have->credential = tag;
|
||||
return ADD_ACCEPTED_NEW;
|
||||
case 1:
|
||||
return ADD_DEFERRED_FOR_WHOIS;
|
||||
}
|
||||
}
|
||||
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap)
|
||||
{
|
||||
_RemoteCredential<Capability> *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)cap.id(),_RemoteCredentialComp<Capability>());
|
||||
_RemoteCredential<Capability> *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)cap.id())) ? *htmp : (_RemoteCredential<Capability> *)0;
|
||||
if (have) {
|
||||
if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > cap.timestamp()) ) {
|
||||
TRACE("addCredential(Capability) for %s on %.16llx REJECTED (revoked or too old)",cap.issuedTo().toString().c_str(),cap.networkId());
|
||||
return ADD_REJECTED;
|
||||
}
|
||||
if (have->credential == cap) {
|
||||
TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (redundant)",cap.issuedTo().toString().c_str(),cap.networkId());
|
||||
return ADD_ACCEPTED_REDUNDANT;
|
||||
}
|
||||
}
|
||||
|
||||
switch(cap.verify(RR)) {
|
||||
default:
|
||||
TRACE("addCredential(Capability) for %s on %.16llx REJECTED (invalid)",cap.issuedTo().toString().c_str(),cap.networkId());
|
||||
return ADD_REJECTED;
|
||||
case 0:
|
||||
TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (new)",cap.issuedTo().toString().c_str(),cap.networkId());
|
||||
if (!have) have = _newCapability(cap.id());
|
||||
have->lastReceived = RR->node->now();
|
||||
have->credential = cap;
|
||||
return ADD_ACCEPTED_NEW;
|
||||
case 1:
|
||||
return ADD_DEFERRED_FOR_WHOIS;
|
||||
}
|
||||
}
|
||||
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Revocation &rev)
|
||||
{
|
||||
switch(rev.verify(RR)) {
|
||||
default:
|
||||
return ADD_REJECTED;
|
||||
case 0: {
|
||||
const uint64_t now = RR->node->now();
|
||||
switch(rev.type()) {
|
||||
default:
|
||||
//case Revocation::CREDENTIAL_TYPE_ALL:
|
||||
return ( (_revokeCom(rev)||_revokeCap(rev,now)||_revokeTag(rev,now)||_revokeCoo(rev,now)) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT );
|
||||
case Revocation::CREDENTIAL_TYPE_COM:
|
||||
return (_revokeCom(rev) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT);
|
||||
case Revocation::CREDENTIAL_TYPE_CAPABILITY:
|
||||
return (_revokeCap(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT);
|
||||
case Revocation::CREDENTIAL_TYPE_TAG:
|
||||
return (_revokeTag(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT);
|
||||
case Revocation::CREDENTIAL_TYPE_COO:
|
||||
return (_revokeCoo(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT);
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
return ADD_DEFERRED_FOR_WHOIS;
|
||||
}
|
||||
}
|
||||
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfOwnership &coo)
|
||||
{
|
||||
_RemoteCredential<CertificateOfOwnership> *const *htmp = std::lower_bound(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),(uint64_t)coo.id(),_RemoteCredentialComp<CertificateOfOwnership>());
|
||||
_RemoteCredential<CertificateOfOwnership> *have = ((htmp != &(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]))&&((*htmp)->id == (uint64_t)coo.id())) ? *htmp : (_RemoteCredential<CertificateOfOwnership> *)0;
|
||||
if (have) {
|
||||
if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > coo.timestamp()) ) {
|
||||
TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx REJECTED (revoked or too old)",coo.issuedTo().toString().c_str(),coo.networkId());
|
||||
return ADD_REJECTED;
|
||||
}
|
||||
if (have->credential == coo) {
|
||||
TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx ACCEPTED (redundant)",coo.issuedTo().toString().c_str(),coo.networkId());
|
||||
return ADD_ACCEPTED_REDUNDANT;
|
||||
}
|
||||
}
|
||||
|
||||
switch(coo.verify(RR)) {
|
||||
default:
|
||||
TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx REJECTED (invalid)",coo.issuedTo().toString().c_str(),coo.networkId());
|
||||
return ADD_REJECTED;
|
||||
case 0:
|
||||
TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx ACCEPTED (new)",coo.issuedTo().toString().c_str(),coo.networkId());
|
||||
if (!have) have = _newCoo(coo.id());
|
||||
have->lastReceived = RR->node->now();
|
||||
have->credential = coo;
|
||||
return ADD_ACCEPTED_NEW;
|
||||
case 1:
|
||||
return ADD_DEFERRED_FOR_WHOIS;
|
||||
}
|
||||
}
|
||||
|
||||
Membership::_RemoteCredential<Tag> *Membership::_newTag(const uint64_t id)
|
||||
{
|
||||
_RemoteCredential<Tag> *t = NULL;
|
||||
uint64_t minlr = 0xffffffffffffffffULL;
|
||||
for(unsigned int i=0;i<ZT_MAX_NETWORK_TAGS;++i) {
|
||||
if (_remoteTags[i]->id == ZT_MEMBERSHIP_CRED_ID_UNUSED) {
|
||||
t = _remoteTags[i];
|
||||
break;
|
||||
} else if (_remoteTags[i]->lastReceived <= minlr) {
|
||||
t = _remoteTags[i];
|
||||
minlr = _remoteTags[i]->lastReceived;
|
||||
}
|
||||
}
|
||||
|
||||
if (t) {
|
||||
t->id = id;
|
||||
t->lastReceived = 0;
|
||||
t->revocationThreshold = 0;
|
||||
t->credential = Tag();
|
||||
}
|
||||
|
||||
std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),_RemoteCredentialComp<Tag>());
|
||||
return t;
|
||||
}
|
||||
|
||||
Membership::_RemoteCredential<Capability> *Membership::_newCapability(const uint64_t id)
|
||||
{
|
||||
_RemoteCredential<Capability> *c = NULL;
|
||||
uint64_t minlr = 0xffffffffffffffffULL;
|
||||
for(unsigned int i=0;i<ZT_MAX_NETWORK_CAPABILITIES;++i) {
|
||||
if (_remoteCaps[i]->id == ZT_MEMBERSHIP_CRED_ID_UNUSED) {
|
||||
c = _remoteCaps[i];
|
||||
break;
|
||||
} else if (_remoteCaps[i]->lastReceived <= minlr) {
|
||||
c = _remoteCaps[i];
|
||||
minlr = _remoteCaps[i]->lastReceived;
|
||||
}
|
||||
}
|
||||
|
||||
if (c) {
|
||||
c->id = id;
|
||||
c->lastReceived = 0;
|
||||
c->revocationThreshold = 0;
|
||||
c->credential = Capability();
|
||||
}
|
||||
|
||||
std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),_RemoteCredentialComp<Capability>());
|
||||
return c;
|
||||
}
|
||||
|
||||
Membership::_RemoteCredential<CertificateOfOwnership> *Membership::_newCoo(const uint64_t id)
|
||||
{
|
||||
_RemoteCredential<CertificateOfOwnership> *c = NULL;
|
||||
uint64_t minlr = 0xffffffffffffffffULL;
|
||||
for(unsigned int i=0;i<ZT_MAX_CERTIFICATES_OF_OWNERSHIP;++i) {
|
||||
if (_remoteCoos[i]->id == ZT_MEMBERSHIP_CRED_ID_UNUSED) {
|
||||
c = _remoteCoos[i];
|
||||
break;
|
||||
} else if (_remoteCoos[i]->lastReceived <= minlr) {
|
||||
c = _remoteCoos[i];
|
||||
minlr = _remoteCoos[i]->lastReceived;
|
||||
}
|
||||
}
|
||||
|
||||
if (c) {
|
||||
c->id = id;
|
||||
c->lastReceived = 0;
|
||||
c->revocationThreshold = 0;
|
||||
c->credential = CertificateOfOwnership();
|
||||
}
|
||||
|
||||
std::sort(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),_RemoteCredentialComp<CertificateOfOwnership>());
|
||||
return c;
|
||||
}
|
||||
|
||||
bool Membership::_revokeCom(const Revocation &rev)
|
||||
{
|
||||
if (rev.threshold() > _comRevocationThreshold) {
|
||||
_comRevocationThreshold = rev.threshold();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Membership::_revokeCap(const Revocation &rev,const uint64_t now)
|
||||
{
|
||||
_RemoteCredential<Capability> *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)rev.credentialId(),_RemoteCredentialComp<Capability>());
|
||||
_RemoteCredential<Capability> *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential<Capability> *)0;
|
||||
if (!have) have = _newCapability(rev.credentialId());
|
||||
if (rev.threshold() > have->revocationThreshold) {
|
||||
have->lastReceived = now;
|
||||
have->revocationThreshold = rev.threshold();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Membership::_revokeTag(const Revocation &rev,const uint64_t now)
|
||||
{
|
||||
_RemoteCredential<Tag> *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)rev.credentialId(),_RemoteCredentialComp<Tag>());
|
||||
_RemoteCredential<Tag> *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential<Tag> *)0;
|
||||
if (!have) have = _newTag(rev.credentialId());
|
||||
if (rev.threshold() > have->revocationThreshold) {
|
||||
have->lastReceived = now;
|
||||
have->revocationThreshold = rev.threshold();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Membership::_revokeCoo(const Revocation &rev,const uint64_t now)
|
||||
{
|
||||
_RemoteCredential<CertificateOfOwnership> *const *htmp = std::lower_bound(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),(uint64_t)rev.credentialId(),_RemoteCredentialComp<CertificateOfOwnership>());
|
||||
_RemoteCredential<CertificateOfOwnership> *have = ((htmp != &(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential<CertificateOfOwnership> *)0;
|
||||
if (!have) have = _newCoo(rev.credentialId());
|
||||
if (rev.threshold() > have->revocationThreshold) {
|
||||
have->lastReceived = now;
|
||||
have->revocationThreshold = rev.threshold();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
299
zerotierone/node/Membership.hpp
Normal file
299
zerotierone/node/Membership.hpp
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_MEMBERSHIP_HPP
|
||||
#define ZT_MEMBERSHIP_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "../include/ZeroTierOne.h"
|
||||
#include "CertificateOfMembership.hpp"
|
||||
#include "Capability.hpp"
|
||||
#include "Tag.hpp"
|
||||
#include "Revocation.hpp"
|
||||
#include "NetworkConfig.hpp"
|
||||
|
||||
#define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
class Network;
|
||||
|
||||
/**
|
||||
* A container for certificates of membership and other network credentials
|
||||
*
|
||||
* This is essentially a relational join between Peer and Network.
|
||||
*
|
||||
* This class is not thread safe. It must be locked externally.
|
||||
*/
|
||||
class Membership
|
||||
{
|
||||
private:
|
||||
template<typename T>
|
||||
struct _RemoteCredential
|
||||
{
|
||||
_RemoteCredential() : id(ZT_MEMBERSHIP_CRED_ID_UNUSED),lastReceived(0),revocationThreshold(0) {}
|
||||
uint64_t id;
|
||||
uint64_t lastReceived; // last time we got this credential
|
||||
uint64_t revocationThreshold; // credentials before this time are invalid
|
||||
T credential;
|
||||
inline bool operator<(const _RemoteCredential &c) const { return (id < c.id); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct _RemoteCredentialComp
|
||||
{
|
||||
inline bool operator()(const _RemoteCredential<T> *a,const _RemoteCredential<T> *b) const { return (a->id < b->id); }
|
||||
inline bool operator()(const uint64_t a,const _RemoteCredential<T> *b) const { return (a < b->id); }
|
||||
inline bool operator()(const _RemoteCredential<T> *a,const uint64_t b) const { return (a->id < b); }
|
||||
inline bool operator()(const uint64_t a,const uint64_t b) const { return (a < b); }
|
||||
};
|
||||
|
||||
// Used to track push state for network config tags[] and capabilities[] entries
|
||||
struct _LocalCredentialPushState
|
||||
{
|
||||
_LocalCredentialPushState() : lastPushed(0),id(0) {}
|
||||
uint64_t lastPushed; // last time we sent our own copy of this credential
|
||||
uint64_t id;
|
||||
};
|
||||
|
||||
public:
|
||||
enum AddCredentialResult
|
||||
{
|
||||
ADD_REJECTED,
|
||||
ADD_ACCEPTED_NEW,
|
||||
ADD_ACCEPTED_REDUNDANT,
|
||||
ADD_DEFERRED_FOR_WHOIS
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterator to scan forward through capabilities in ascending order of ID
|
||||
*/
|
||||
class CapabilityIterator
|
||||
{
|
||||
public:
|
||||
CapabilityIterator(const Membership &m,const NetworkConfig &nconf) :
|
||||
_m(&m),
|
||||
_c(&nconf),
|
||||
_i(&(m._remoteCaps[0])) {}
|
||||
|
||||
inline const Capability *next()
|
||||
{
|
||||
for(;;) {
|
||||
if ((_i != &(_m->_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) {
|
||||
const Capability *tmp = &((*_i)->credential);
|
||||
if (_m->_isCredentialTimestampValid(*_c,**_i)) {
|
||||
++_i;
|
||||
return tmp;
|
||||
} else ++_i;
|
||||
} else {
|
||||
return (const Capability *)0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const Membership *_m;
|
||||
const NetworkConfig *_c;
|
||||
const _RemoteCredential<Capability> *const *_i;
|
||||
};
|
||||
friend class CapabilityIterator;
|
||||
|
||||
/**
|
||||
* Iterator to scan forward through tags in ascending order of ID
|
||||
*/
|
||||
class TagIterator
|
||||
{
|
||||
public:
|
||||
TagIterator(const Membership &m,const NetworkConfig &nconf) :
|
||||
_m(&m),
|
||||
_c(&nconf),
|
||||
_i(&(m._remoteTags[0])) {}
|
||||
|
||||
inline const Tag *next()
|
||||
{
|
||||
for(;;) {
|
||||
if ((_i != &(_m->_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) {
|
||||
const Tag *tmp = &((*_i)->credential);
|
||||
if (_m->_isCredentialTimestampValid(*_c,**_i)) {
|
||||
++_i;
|
||||
return tmp;
|
||||
} else ++_i;
|
||||
} else {
|
||||
return (const Tag *)0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const Membership *_m;
|
||||
const NetworkConfig *_c;
|
||||
const _RemoteCredential<Tag> *const *_i;
|
||||
};
|
||||
friend class TagIterator;
|
||||
|
||||
Membership();
|
||||
|
||||
/**
|
||||
* Send COM and other credentials to this peer if needed
|
||||
*
|
||||
* This checks last pushed times for our COM and for other credentials and
|
||||
* sends VERB_NETWORK_CREDENTIALS if the recipient might need them.
|
||||
*
|
||||
* @param RR Runtime environment
|
||||
* @param now Current time
|
||||
* @param peerAddress Address of member peer (the one that this Membership describes)
|
||||
* @param nconf My network config
|
||||
* @param localCapabilityIndex Index of local capability to include (in nconf.capabilities[]) or -1 if none
|
||||
* @param force If true, send objects regardless of last push time
|
||||
*/
|
||||
void pushCredentials(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force);
|
||||
|
||||
/**
|
||||
* Check whether we should push MULTICAST_LIKEs to this peer
|
||||
*
|
||||
* @param now Current time
|
||||
* @return True if we should update multicasts
|
||||
*/
|
||||
inline bool shouldLikeMulticasts(const uint64_t now) const { return ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD); }
|
||||
|
||||
/**
|
||||
* Set time we last updated multicasts for this peer
|
||||
*
|
||||
* @param now Current time
|
||||
*/
|
||||
inline void likingMulticasts(const uint64_t now) { _lastUpdatedMulticast = now; }
|
||||
|
||||
/**
|
||||
* Check whether the peer represented by this Membership should be allowed on this network at all
|
||||
*
|
||||
* @param nconf Our network config
|
||||
* @return True if this peer is allowed on this network at all
|
||||
*/
|
||||
inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const
|
||||
{
|
||||
if (nconf.isPublic())
|
||||
return true;
|
||||
if (_com.timestamp().first <= _comRevocationThreshold)
|
||||
return false;
|
||||
return nconf.com.agreesWith(_com);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the peer represented by this Membership owns a given resource
|
||||
*
|
||||
* @tparam Type of resource: InetAddress or MAC
|
||||
* @param nconf Our network config
|
||||
* @param r Resource to check
|
||||
* @return True if this peer has a certificate of ownership for the given resource
|
||||
*/
|
||||
template<typename T>
|
||||
inline bool hasCertificateOfOwnershipFor(const NetworkConfig &nconf,const T &r) const
|
||||
{
|
||||
for(unsigned int i=0;i<ZT_MAX_CERTIFICATES_OF_OWNERSHIP;++i) {
|
||||
if (_remoteCoos[i]->id == ZT_MEMBERSHIP_CRED_ID_UNUSED)
|
||||
break;
|
||||
if ((_isCredentialTimestampValid(nconf,*_remoteCoos[i]))&&(_remoteCoos[i]->credential.owns(r)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nconf Network configuration
|
||||
* @param id Tag ID
|
||||
* @return Pointer to tag or NULL if not found
|
||||
*/
|
||||
const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const;
|
||||
|
||||
/**
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
*/
|
||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfMembership &com);
|
||||
|
||||
/**
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
*/
|
||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Tag &tag);
|
||||
|
||||
/**
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
*/
|
||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap);
|
||||
|
||||
/**
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
*/
|
||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Revocation &rev);
|
||||
|
||||
/**
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
*/
|
||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfOwnership &coo);
|
||||
|
||||
private:
|
||||
_RemoteCredential<Tag> *_newTag(const uint64_t id);
|
||||
_RemoteCredential<Capability> *_newCapability(const uint64_t id);
|
||||
_RemoteCredential<CertificateOfOwnership> *_newCoo(const uint64_t id);
|
||||
bool _revokeCom(const Revocation &rev);
|
||||
bool _revokeCap(const Revocation &rev,const uint64_t now);
|
||||
bool _revokeTag(const Revocation &rev,const uint64_t now);
|
||||
bool _revokeCoo(const Revocation &rev,const uint64_t now);
|
||||
|
||||
template<typename C>
|
||||
inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const _RemoteCredential<C> &remoteCredential) const
|
||||
{
|
||||
if (!remoteCredential.lastReceived)
|
||||
return false;
|
||||
const uint64_t ts = remoteCredential.credential.timestamp();
|
||||
return ( (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) && (ts > remoteCredential.revocationThreshold) );
|
||||
}
|
||||
|
||||
// Last time we pushed MULTICAST_LIKE(s)
|
||||
uint64_t _lastUpdatedMulticast;
|
||||
|
||||
// Last time we pushed our COM to this peer
|
||||
uint64_t _lastPushedCom;
|
||||
|
||||
// Revocation threshold for COM or 0 if none
|
||||
uint64_t _comRevocationThreshold;
|
||||
|
||||
// Remote member's latest network COM
|
||||
CertificateOfMembership _com;
|
||||
|
||||
// Sorted (in ascending order of ID) arrays of pointers to remote credentials
|
||||
_RemoteCredential<Tag> *_remoteTags[ZT_MAX_NETWORK_TAGS];
|
||||
_RemoteCredential<Capability> *_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES];
|
||||
_RemoteCredential<CertificateOfOwnership> *_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
|
||||
|
||||
// This is the RAM allocated for remote credential cache objects
|
||||
_RemoteCredential<Tag> _tagMem[ZT_MAX_NETWORK_TAGS];
|
||||
_RemoteCredential<Capability> _capMem[ZT_MAX_NETWORK_CAPABILITIES];
|
||||
_RemoteCredential<CertificateOfOwnership> _cooMem[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
|
||||
|
||||
// Local credential push state tracking
|
||||
_LocalCredentialPushState _localTags[ZT_MAX_NETWORK_TAGS];
|
||||
_LocalCredentialPushState _localCaps[ZT_MAX_NETWORK_CAPABILITIES];
|
||||
_LocalCredentialPushState _localCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
14
zerotierone/node/README.md
Normal file
14
zerotierone/node/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
ZeroTier Network Hypervisor Core
|
||||
======
|
||||
|
||||
This directory contains the *real* ZeroTier: a completely OS-independent global virtual Ethernet switch engine. This is where the magic happens.
|
||||
|
||||
Give it wire packets and it gives you Ethernet packets, and vice versa. The core contains absolutely no actual I/O, port configuration, or other OS-specific code (except Utils::getSecureRandom()). It provides a simple C API via [/include/ZeroTierOne.h](../include/ZeroTierOne.h). It's designed to be small and maximally portable for future use on small embedded and special purpose systems.
|
||||
|
||||
Code in here follows these guidelines:
|
||||
|
||||
- Keep it minimal, especially in terms of code footprint and memory use.
|
||||
- There should be no OS-dependent code here unless absolutely necessary (e.g. getSecureRandom).
|
||||
- If it's not part of the core virtual Ethernet switch it does not belong here.
|
||||
- No C++11 or C++14 since older and embedded compilers don't support it yet and this should be maximally portable.
|
||||
- Minimize the use of complex C++ features since at some point we might end up "minus-minus'ing" this code if doing so proves necessary to port to tiny embedded systems.
|
||||
46
zerotierone/node/Revocation.cpp
Normal file
46
zerotierone/node/Revocation.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Revocation.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Switch.hpp"
|
||||
#include "Network.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
int Revocation::verify(const RuntimeEnvironment *RR) const
|
||||
{
|
||||
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
|
||||
return -1;
|
||||
const Identity id(RR->topology->getIdentity(_signedBy));
|
||||
if (!id) {
|
||||
RR->sw->requestWhois(_signedBy);
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
Buffer<sizeof(Revocation) + 64> tmp;
|
||||
this->serialize(tmp,true);
|
||||
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
|
||||
} catch ( ... ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
181
zerotierone/node/Revocation.hpp
Normal file
181
zerotierone/node/Revocation.hpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_REVOCATION_HPP
|
||||
#define ZT_REVOCATION_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "../include/ZeroTierOne.h"
|
||||
#include "Address.hpp"
|
||||
#include "C25519.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "Identity.hpp"
|
||||
|
||||
/**
|
||||
* Flag: fast propagation via rumor mill algorithm
|
||||
*/
|
||||
#define ZT_REVOCATION_FLAG_FAST_PROPAGATE 0x1ULL
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
|
||||
/**
|
||||
* Revocation certificate to instantaneously revoke a COM, capability, or tag
|
||||
*/
|
||||
class Revocation
|
||||
{
|
||||
public:
|
||||
enum CredentialType
|
||||
{
|
||||
CREDENTIAL_TYPE_ALL = 0,
|
||||
CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership
|
||||
CREDENTIAL_TYPE_CAPABILITY = 2,
|
||||
CREDENTIAL_TYPE_TAG = 3,
|
||||
CREDENTIAL_TYPE_COO = 4 // CertificateOfOwnership
|
||||
};
|
||||
|
||||
Revocation()
|
||||
{
|
||||
memset(this,0,sizeof(Revocation));
|
||||
}
|
||||
|
||||
Revocation(const uint64_t i,const uint64_t nwid,const uint64_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const CredentialType ct) :
|
||||
_id(i),
|
||||
_networkId(nwid),
|
||||
_credentialId(cid),
|
||||
_threshold(thr),
|
||||
_flags(fl),
|
||||
_target(tgt),
|
||||
_signedBy(),
|
||||
_type(ct) {}
|
||||
|
||||
inline uint64_t id() const { return _id; }
|
||||
inline uint64_t networkId() const { return _networkId; }
|
||||
inline uint64_t credentialId() const { return _credentialId; }
|
||||
inline uint64_t threshold() const { return _threshold; }
|
||||
inline const Address &target() const { return _target; }
|
||||
inline const Address &signer() const { return _signedBy; }
|
||||
inline CredentialType type() const { return _type; }
|
||||
|
||||
inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
|
||||
|
||||
/**
|
||||
* @param signer Signing identity, must have private key
|
||||
* @return True if signature was successful
|
||||
*/
|
||||
inline bool sign(const Identity &signer)
|
||||
{
|
||||
if (signer.hasPrivate()) {
|
||||
Buffer<sizeof(Revocation) + 64> tmp;
|
||||
_signedBy = signer.address();
|
||||
this->serialize(tmp,true);
|
||||
_signature = signer.sign(tmp.data(),tmp.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify this revocation's signature
|
||||
*
|
||||
* @param RR Runtime environment to provide for peer lookup, etc.
|
||||
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain
|
||||
*/
|
||||
int verify(const RuntimeEnvironment *RR) const;
|
||||
|
||||
template<unsigned int C>
|
||||
inline void serialize(Buffer<C> &b,const bool forSign = false) const
|
||||
{
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
|
||||
b.append(_id);
|
||||
b.append(_networkId);
|
||||
b.append(_credentialId);
|
||||
b.append(_threshold);
|
||||
b.append(_flags);
|
||||
_target.appendTo(b);
|
||||
_signedBy.appendTo(b);
|
||||
b.append((uint8_t)_type);
|
||||
|
||||
if (!forSign) {
|
||||
b.append((uint8_t)1); // 1 == Ed25519 signature
|
||||
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN);
|
||||
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
|
||||
}
|
||||
|
||||
// This is the size of any additional fields, currently 0.
|
||||
b.append((uint16_t)0);
|
||||
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
|
||||
{
|
||||
memset(this,0,sizeof(Revocation));
|
||||
|
||||
unsigned int p = startAt;
|
||||
|
||||
_id = b.template at<uint64_t>(p); p += 8;
|
||||
_networkId = b.template at<uint64_t>(p); p += 8;
|
||||
_credentialId = b.template at<uint64_t>(p); p += 8;
|
||||
_threshold = b.template at<uint64_t>(p); p += 8;
|
||||
_flags = b.template at<uint64_t>(p); p += 8;
|
||||
_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||
_type = (CredentialType)b[p++];
|
||||
|
||||
if (b[p++] == 1) {
|
||||
if (b.template at<uint16_t>(p) == ZT_C25519_SIGNATURE_LEN) {
|
||||
p += 2;
|
||||
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
|
||||
p += ZT_C25519_SIGNATURE_LEN;
|
||||
} else throw std::runtime_error("invalid signature");
|
||||
} else {
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
}
|
||||
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
if (p > b.size())
|
||||
throw std::runtime_error("extended field overflow");
|
||||
|
||||
return (p - startAt);
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t _id;
|
||||
uint64_t _networkId;
|
||||
uint64_t _credentialId;
|
||||
uint64_t _threshold;
|
||||
uint64_t _flags;
|
||||
Address _target;
|
||||
Address _signedBy;
|
||||
CredentialType _type;
|
||||
C25519::Signature _signature;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
46
zerotierone/node/Tag.cpp
Normal file
46
zerotierone/node/Tag.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Tag.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Switch.hpp"
|
||||
#include "Network.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
int Tag::verify(const RuntimeEnvironment *RR) const
|
||||
{
|
||||
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
|
||||
return -1;
|
||||
const Identity id(RR->topology->getIdentity(_signedBy));
|
||||
if (!id) {
|
||||
RR->sw->requestWhois(_signedBy);
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
Buffer<(sizeof(Tag) * 2)> tmp;
|
||||
this->serialize(tmp,true);
|
||||
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
|
||||
} catch ( ... ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
200
zerotierone/node/Tag.hpp
Normal file
200
zerotierone/node/Tag.hpp
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_TAG_HPP
|
||||
#define ZT_TAG_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "C25519.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "Buffer.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
|
||||
/**
|
||||
* A tag that can be associated with members and matched in rules
|
||||
*
|
||||
* Capabilities group rules, while tags group members subject to those
|
||||
* rules. Tag values can be matched in rules, and tags relevant to a
|
||||
* capability are presented along with it.
|
||||
*
|
||||
* E.g. a capability might be "can speak Samba/CIFS within your
|
||||
* department." This cap might have a rule to allow TCP/137 but
|
||||
* only if a given tag ID's value matches between two peers. The
|
||||
* capability is what members can do, while the tag is who they are.
|
||||
* Different departments might have tags with the same ID but different
|
||||
* values.
|
||||
*
|
||||
* Unlike capabilities tags are signed only by the issuer and are never
|
||||
* transferrable.
|
||||
*/
|
||||
class Tag
|
||||
{
|
||||
public:
|
||||
Tag()
|
||||
{
|
||||
memset(this,0,sizeof(Tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nwid Network ID
|
||||
* @param ts Timestamp
|
||||
* @param issuedTo Address to which this tag was issued
|
||||
* @param id Tag ID
|
||||
* @param value Tag value
|
||||
*/
|
||||
Tag(const uint64_t nwid,const uint64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) :
|
||||
_networkId(nwid),
|
||||
_ts(ts),
|
||||
_id(id),
|
||||
_value(value),
|
||||
_issuedTo(issuedTo),
|
||||
_signedBy()
|
||||
{
|
||||
}
|
||||
|
||||
inline uint64_t networkId() const { return _networkId; }
|
||||
inline uint64_t timestamp() const { return _ts; }
|
||||
inline uint32_t id() const { return _id; }
|
||||
inline const uint32_t &value() const { return _value; }
|
||||
inline const Address &issuedTo() const { return _issuedTo; }
|
||||
inline const Address &signedBy() const { return _signedBy; }
|
||||
|
||||
/**
|
||||
* Sign this tag
|
||||
*
|
||||
* @param signer Signing identity, must have private key
|
||||
* @return True if signature was successful
|
||||
*/
|
||||
inline bool sign(const Identity &signer)
|
||||
{
|
||||
if (signer.hasPrivate()) {
|
||||
Buffer<sizeof(Tag) + 64> tmp;
|
||||
_signedBy = signer.address();
|
||||
this->serialize(tmp,true);
|
||||
_signature = signer.sign(tmp.data(),tmp.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check this tag's signature
|
||||
*
|
||||
* @param RR Runtime environment to allow identity lookup for signedBy
|
||||
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag
|
||||
*/
|
||||
int verify(const RuntimeEnvironment *RR) const;
|
||||
|
||||
template<unsigned int C>
|
||||
inline void serialize(Buffer<C> &b,const bool forSign = false) const
|
||||
{
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
|
||||
// These are the same between Tag and Capability
|
||||
b.append(_networkId);
|
||||
b.append(_ts);
|
||||
b.append(_id);
|
||||
|
||||
b.append(_value);
|
||||
|
||||
_issuedTo.appendTo(b);
|
||||
_signedBy.appendTo(b);
|
||||
if (!forSign) {
|
||||
b.append((uint8_t)1); // 1 == Ed25519
|
||||
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
|
||||
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
|
||||
}
|
||||
|
||||
b.append((uint16_t)0); // length of additional fields, currently 0
|
||||
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
|
||||
{
|
||||
unsigned int p = startAt;
|
||||
|
||||
memset(this,0,sizeof(Tag));
|
||||
|
||||
_networkId = b.template at<uint64_t>(p); p += 8;
|
||||
_ts = b.template at<uint64_t>(p); p += 8;
|
||||
_id = b.template at<uint32_t>(p); p += 4;
|
||||
|
||||
_value = b.template at<uint32_t>(p); p += 4;
|
||||
|
||||
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||
if (b[p++] == 1) {
|
||||
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
|
||||
throw std::runtime_error("invalid signature length");
|
||||
p += 2;
|
||||
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
|
||||
} else {
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
}
|
||||
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
if (p > b.size())
|
||||
throw std::runtime_error("extended field overflow");
|
||||
|
||||
return (p - startAt);
|
||||
}
|
||||
|
||||
// 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 (memcmp(this,&t,sizeof(Tag)) == 0); }
|
||||
inline bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); }
|
||||
|
||||
// For searching sorted arrays or lists of Tags by ID
|
||||
struct IdComparePredicate
|
||||
{
|
||||
inline bool operator()(const Tag &a,const Tag &b) const { return (a.id() < b.id()); }
|
||||
inline bool operator()(const uint32_t a,const Tag &b) const { return (a < b.id()); }
|
||||
inline bool operator()(const Tag &a,const uint32_t b) const { return (a.id() < b); }
|
||||
inline bool operator()(const Tag *a,const Tag *b) const { return (a->id() < b->id()); }
|
||||
inline bool operator()(const Tag *a,const Tag &b) const { return (a->id() < b.id()); }
|
||||
inline bool operator()(const Tag &a,const Tag *b) const { return (a.id() < b->id()); }
|
||||
inline bool operator()(const uint32_t a,const Tag *b) const { return (a < b->id()); }
|
||||
inline bool operator()(const Tag *a,const uint32_t b) const { return (a->id() < b); }
|
||||
inline bool operator()(const uint32_t a,const uint32_t b) const { return (a < b); }
|
||||
};
|
||||
|
||||
private:
|
||||
uint64_t _networkId;
|
||||
uint64_t _ts;
|
||||
uint32_t _id;
|
||||
uint32_t _value;
|
||||
Address _issuedTo;
|
||||
Address _signedBy;
|
||||
C25519::Signature _signature;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
64
zerotierone/osdep/BlockingQueue.hpp
Normal file
64
zerotierone/osdep/BlockingQueue.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_BLOCKINGQUEUE_HPP
|
||||
#define ZT_BLOCKINGQUEUE_HPP
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Simple C++11 thread-safe queue
|
||||
*
|
||||
* Do not use in node/ since we have not gone C++11 there yet.
|
||||
*/
|
||||
template <class T>
|
||||
class BlockingQueue
|
||||
{
|
||||
public:
|
||||
BlockingQueue(void) {}
|
||||
|
||||
inline void post(T t)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
q.push(t);
|
||||
c.notify_one();
|
||||
}
|
||||
|
||||
inline T get(void)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m);
|
||||
while(q.empty())
|
||||
c.wait(lock);
|
||||
T val = q.front();
|
||||
q.pop();
|
||||
return val;
|
||||
}
|
||||
|
||||
private:
|
||||
std::queue<T> q;
|
||||
mutable std::mutex m;
|
||||
std::condition_variable c;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
264
zerotierone/osdep/NeighborDiscovery.cpp
Normal file
264
zerotierone/osdep/NeighborDiscovery.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "NeighborDiscovery.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
|
||||
#include "../include/ZeroTierOne.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
uint16_t calc_checksum (uint16_t *addr, int len)
|
||||
{
|
||||
int count = len;
|
||||
uint32_t sum = 0;
|
||||
uint16_t answer = 0;
|
||||
|
||||
// Sum up 2-byte values until none or only one byte left.
|
||||
while (count > 1) {
|
||||
sum += *(addr++);
|
||||
count -= 2;
|
||||
}
|
||||
|
||||
// Add left-over byte, if any.
|
||||
if (count > 0) {
|
||||
sum += *(uint8_t *) addr;
|
||||
}
|
||||
|
||||
// Fold 32-bit sum into 16 bits; we lose information by doing this,
|
||||
// increasing the chances of a collision.
|
||||
// sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
|
||||
while (sum >> 16) {
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
}
|
||||
|
||||
// Checksum is one's compliment of sum.
|
||||
answer = ~sum;
|
||||
|
||||
return (answer);
|
||||
}
|
||||
|
||||
struct _pseudo_header {
|
||||
uint8_t sourceAddr[16];
|
||||
uint8_t targetAddr[16];
|
||||
uint32_t length;
|
||||
uint8_t zeros[3];
|
||||
uint8_t next; // 58
|
||||
};
|
||||
|
||||
struct _option {
|
||||
_option(int optionType)
|
||||
: type(optionType)
|
||||
, length(8)
|
||||
{
|
||||
memset(mac, 0, sizeof(mac));
|
||||
}
|
||||
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
uint8_t mac[6];
|
||||
};
|
||||
|
||||
struct _neighbor_solicitation {
|
||||
_neighbor_solicitation()
|
||||
: type(135)
|
||||
, code(0)
|
||||
, checksum(0)
|
||||
, option(1)
|
||||
{
|
||||
memset(&reserved, 0, sizeof(reserved));
|
||||
memset(target, 0, sizeof(target));
|
||||
}
|
||||
|
||||
void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) {
|
||||
_pseudo_header ph;
|
||||
memset(&ph, 0, sizeof(_pseudo_header));
|
||||
const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp;
|
||||
const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp;
|
||||
|
||||
memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
|
||||
memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
|
||||
ph.next = 58;
|
||||
ph.length = htonl(sizeof(_neighbor_solicitation));
|
||||
|
||||
size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_solicitation);
|
||||
uint8_t *tmp = (uint8_t*)malloc(len);
|
||||
memcpy(tmp, &ph, sizeof(_pseudo_header));
|
||||
memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_solicitation));
|
||||
|
||||
checksum = calc_checksum((uint16_t*)tmp, (int)len);
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
uint8_t type; // 135
|
||||
uint8_t code; // 0
|
||||
uint16_t checksum;
|
||||
uint32_t reserved;
|
||||
uint8_t target[16];
|
||||
_option option;
|
||||
};
|
||||
|
||||
struct _neighbor_advertisement {
|
||||
_neighbor_advertisement()
|
||||
: type(136)
|
||||
, code(0)
|
||||
, checksum(0)
|
||||
, rso(0x40)
|
||||
, option(2)
|
||||
{
|
||||
memset(padding, 0, sizeof(padding));
|
||||
memset(target, 0, sizeof(target));
|
||||
}
|
||||
|
||||
void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) {
|
||||
_pseudo_header ph;
|
||||
memset(&ph, 0, sizeof(_pseudo_header));
|
||||
const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp;
|
||||
const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp;
|
||||
|
||||
memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
|
||||
memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
|
||||
ph.next = 58;
|
||||
ph.length = htonl(sizeof(_neighbor_advertisement));
|
||||
|
||||
size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_advertisement);
|
||||
uint8_t *tmp = (uint8_t*)malloc(len);
|
||||
memcpy(tmp, &ph, sizeof(_pseudo_header));
|
||||
memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_advertisement));
|
||||
|
||||
checksum = calc_checksum((uint16_t*)tmp, (int)len);
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
uint8_t type; // 136
|
||||
uint8_t code; // 0
|
||||
uint16_t checksum;
|
||||
uint8_t rso;
|
||||
uint8_t padding[3];
|
||||
uint8_t target[16];
|
||||
_option option;
|
||||
};
|
||||
|
||||
NeighborDiscovery::NeighborDiscovery()
|
||||
: _cache(256)
|
||||
, _lastCleaned(OSUtils::now())
|
||||
{}
|
||||
|
||||
void NeighborDiscovery::addLocal(const sockaddr_storage &address, const MAC &mac)
|
||||
{
|
||||
_NDEntry &e = _cache[InetAddress(address)];
|
||||
e.lastQuerySent = 0;
|
||||
e.lastResponseReceived = 0;
|
||||
e.mac = mac;
|
||||
e.local = true;
|
||||
}
|
||||
|
||||
void NeighborDiscovery::remove(const sockaddr_storage &address)
|
||||
{
|
||||
_cache.erase(InetAddress(address));
|
||||
}
|
||||
|
||||
sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest)
|
||||
{
|
||||
assert(sizeof(_neighbor_solicitation) == 28);
|
||||
assert(sizeof(_neighbor_advertisement) == 32);
|
||||
|
||||
const uint64_t now = OSUtils::now();
|
||||
sockaddr_storage ip = ZT_SOCKADDR_NULL;
|
||||
|
||||
if (len >= sizeof(_neighbor_solicitation) && nd[0] == 0x87) {
|
||||
// respond to Neighbor Solicitation request for local address
|
||||
_neighbor_solicitation solicitation;
|
||||
memcpy(&solicitation, nd, len);
|
||||
InetAddress targetAddress(solicitation.target, 16, 0);
|
||||
_NDEntry *targetEntry = _cache.get(targetAddress);
|
||||
if (targetEntry && targetEntry->local) {
|
||||
_neighbor_advertisement adv;
|
||||
targetEntry->mac.copyTo(adv.option.mac, 6);
|
||||
memcpy(adv.target, solicitation.target, 16);
|
||||
adv.calculateChecksum(localIp, targetAddress);
|
||||
memcpy(response, &adv, sizeof(_neighbor_advertisement));
|
||||
responseLen = sizeof(_neighbor_advertisement);
|
||||
responseDest.setTo(solicitation.option.mac, 6);
|
||||
}
|
||||
} else if (len >= sizeof(_neighbor_advertisement) && nd[0] == 0x88) {
|
||||
_neighbor_advertisement adv;
|
||||
memcpy(&adv, nd, len);
|
||||
InetAddress responseAddress(adv.target, 16, 0);
|
||||
_NDEntry *queryEntry = _cache.get(responseAddress);
|
||||
if(queryEntry && !queryEntry->local && (now - queryEntry->lastQuerySent <= ZT_ND_QUERY_MAX_TTL)) {
|
||||
queryEntry->lastResponseReceived = now;
|
||||
queryEntry->mac.setTo(adv.option.mac, 6);
|
||||
ip = responseAddress;
|
||||
}
|
||||
}
|
||||
|
||||
if ((now - _lastCleaned) >= ZT_ND_EXPIRE) {
|
||||
_lastCleaned = now;
|
||||
Hashtable<InetAddress, _NDEntry>::Iterator i(_cache);
|
||||
InetAddress *k = NULL;
|
||||
_NDEntry *v = NULL;
|
||||
while (i.next(k, v)) {
|
||||
if(!v->local && (now - v->lastResponseReceived) >= ZT_ND_EXPIRE) {
|
||||
_cache.erase(*k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
MAC NeighborDiscovery::query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest)
|
||||
{
|
||||
const uint64_t now = OSUtils::now();
|
||||
|
||||
InetAddress localAddress(localIp);
|
||||
localAddress.setPort(0);
|
||||
InetAddress targetAddress(targetIp);
|
||||
targetAddress.setPort(0);
|
||||
|
||||
_NDEntry &e = _cache[targetAddress];
|
||||
|
||||
if ( (e.mac && ((now - e.lastResponseReceived) >= (ZT_ND_EXPIRE / 3))) ||
|
||||
(!e.mac && ((now - e.lastQuerySent) >= ZT_ND_QUERY_INTERVAL))) {
|
||||
e.lastQuerySent = now;
|
||||
|
||||
_neighbor_solicitation ns;
|
||||
memcpy(ns.target, targetAddress.rawIpData(), 16);
|
||||
localMac.copyTo(ns.option.mac, 6);
|
||||
ns.calculateChecksum(localIp, targetIp);
|
||||
if (e.mac) {
|
||||
queryDest = e.mac;
|
||||
} else {
|
||||
queryDest = (uint64_t)0xffffffffffffULL;
|
||||
}
|
||||
} else {
|
||||
queryLen = 0;
|
||||
queryDest.zero();
|
||||
}
|
||||
|
||||
return e.mac;
|
||||
}
|
||||
|
||||
}
|
||||
76
zerotierone/osdep/NeighborDiscovery.hpp
Normal file
76
zerotierone/osdep/NeighborDiscovery.hpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_NEIGHBORDISCOVERY_HPP
|
||||
#define ZT_NEIGHBORDISCOVERY_HPP
|
||||
|
||||
#include "../node/Hashtable.hpp"
|
||||
#include "../node/MAC.hpp"
|
||||
#include "../node/InetAddress.hpp"
|
||||
|
||||
|
||||
#define ZT_ND_QUERY_INTERVAL 2000
|
||||
|
||||
#define ZT_ND_QUERY_MAX_TTL 5000
|
||||
|
||||
#define ZT_ND_EXPIRE 600000
|
||||
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class NeighborDiscovery
|
||||
{
|
||||
public:
|
||||
NeighborDiscovery();
|
||||
|
||||
/**
|
||||
* Set a local IP entry that we should respond to Neighbor Requests withPrefix64k
|
||||
*
|
||||
* @param mac Our local MAC address
|
||||
* @param ip Our IPv6 address
|
||||
*/
|
||||
void addLocal(const sockaddr_storage &address, const MAC &mac);
|
||||
|
||||
/**
|
||||
* Delete a local IP entry or cached Neighbor entry
|
||||
*
|
||||
* @param address IPv6 address to remove
|
||||
*/
|
||||
void remove(const sockaddr_storage &address);
|
||||
|
||||
sockaddr_storage processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest);
|
||||
|
||||
MAC query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest);
|
||||
|
||||
private:
|
||||
struct _NDEntry
|
||||
{
|
||||
_NDEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false) {}
|
||||
uint64_t lastQuerySent;
|
||||
uint64_t lastResponseReceived;
|
||||
MAC mac;
|
||||
bool local;
|
||||
};
|
||||
|
||||
Hashtable<InetAddress, _NDEntry> _cache;
|
||||
uint64_t _lastCleaned;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
432
zerotierone/service/SoftwareUpdater.cpp
Normal file
432
zerotierone/service/SoftwareUpdater.cpp
Normal file
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../version.h"
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <WinSock2.h>
|
||||
#include <Windows.h>
|
||||
#include <ShlObj.h>
|
||||
#include <netioapi.h>
|
||||
#include <iphlpapi.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include "SoftwareUpdater.hpp"
|
||||
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/SHA512.hpp"
|
||||
#include "../node/Buffer.hpp"
|
||||
#include "../node/Node.hpp"
|
||||
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
|
||||
#ifndef ZT_BUILD_ARCHITECTURE
|
||||
#define ZT_BUILD_ARCHITECTURE 0
|
||||
#endif
|
||||
#ifndef ZT_BUILD_PLATFORM
|
||||
#define ZT_BUILD_PLATFORM 0
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
SoftwareUpdater::SoftwareUpdater(Node &node,const std::string &homePath) :
|
||||
_node(node),
|
||||
_lastCheckTime(0),
|
||||
_homePath(homePath),
|
||||
_channel(ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL),
|
||||
_distLog((FILE *)0),
|
||||
_latestValid(false),
|
||||
_downloadLength(0)
|
||||
{
|
||||
// Check for a cached newer update. If there's a cached update that is not newer or looks bad, delete.
|
||||
try {
|
||||
std::string buf;
|
||||
if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_META_FILENAME).c_str(),buf)) {
|
||||
nlohmann::json meta = OSUtils::jsonParse(buf);
|
||||
buf = std::string();
|
||||
const unsigned int rvMaj = (unsigned int)OSUtils::jsonInt(meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR],0);
|
||||
const unsigned int rvMin = (unsigned int)OSUtils::jsonInt(meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR],0);
|
||||
const unsigned int rvRev = (unsigned int)OSUtils::jsonInt(meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION],0);
|
||||
const unsigned int rvBld = (unsigned int)OSUtils::jsonInt(meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD],0);
|
||||
if ((Utils::compareVersion(rvMaj,rvMin,rvRev,rvBld,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION,ZEROTIER_ONE_VERSION_BUILD) > 0)&&
|
||||
(OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str(),buf))) {
|
||||
if ((uint64_t)buf.length() == OSUtils::jsonInt(meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE],0)) {
|
||||
_latestMeta = meta;
|
||||
_latestValid = true;
|
||||
//printf("CACHED UPDATE IS NEWER AND LOOKS GOOD\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {} // exceptions indicate invalid cached update
|
||||
if (!_latestValid) {
|
||||
OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_META_FILENAME).c_str());
|
||||
OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
SoftwareUpdater::~SoftwareUpdater()
|
||||
{
|
||||
if (_distLog)
|
||||
fclose(_distLog);
|
||||
}
|
||||
|
||||
void SoftwareUpdater::setUpdateDistribution(bool distribute)
|
||||
{
|
||||
_dist.clear();
|
||||
if (distribute) {
|
||||
_distLog = fopen((_homePath + ZT_PATH_SEPARATOR_S "update-dist.log").c_str(),"a");
|
||||
|
||||
const std::string udd(_homePath + ZT_PATH_SEPARATOR_S "update-dist.d");
|
||||
const std::vector<std::string> ud(OSUtils::listDirectory(udd.c_str()));
|
||||
for(std::vector<std::string>::const_iterator u(ud.begin());u!=ud.end();++u) {
|
||||
// Each update has a companion .json file describing it. Other files are ignored.
|
||||
if ((u->length() > 5)&&(u->substr(u->length() - 5,5) == ".json")) {
|
||||
|
||||
std::string buf;
|
||||
if (OSUtils::readFile((udd + ZT_PATH_SEPARATOR_S + *u).c_str(),buf)) {
|
||||
try {
|
||||
_D d;
|
||||
d.meta = OSUtils::jsonParse(buf); // throws on invalid JSON
|
||||
|
||||
// If update meta is called e.g. foo.exe.json, then foo.exe is the update itself
|
||||
const std::string binPath(udd + ZT_PATH_SEPARATOR_S + u->substr(0,u->length() - 5));
|
||||
const std::string metaHash(OSUtils::jsonBinFromHex(d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH]));
|
||||
if ((metaHash.length() == ZT_SHA512_DIGEST_LEN)&&(OSUtils::readFile(binPath.c_str(),d.bin))) {
|
||||
uint8_t sha512[ZT_SHA512_DIGEST_LEN];
|
||||
SHA512::hash(sha512,d.bin.data(),(unsigned int)d.bin.length());
|
||||
if (!memcmp(sha512,metaHash.data(),ZT_SHA512_DIGEST_LEN)) { // double check that hash in JSON is correct
|
||||
d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE] = d.bin.length(); // override with correct value -- setting this in meta json is optional
|
||||
_dist[Array<uint8_t,16>(sha512)] = d;
|
||||
if (_distLog) {
|
||||
fprintf(_distLog,".......... INIT: DISTRIBUTING %s (%u bytes)" ZT_EOL_S,binPath.c_str(),(unsigned int)d.bin.length());
|
||||
fflush(_distLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {} // ignore bad meta JSON, etc.
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_distLog) {
|
||||
fclose(_distLog);
|
||||
_distLog = (FILE *)0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void *data,unsigned int len)
|
||||
{
|
||||
if (!len) return;
|
||||
const MessageVerb v = (MessageVerb)reinterpret_cast<const uint8_t *>(data)[0];
|
||||
try {
|
||||
switch(v) {
|
||||
|
||||
case VERB_GET_LATEST:
|
||||
case VERB_LATEST: {
|
||||
nlohmann::json req = OSUtils::jsonParse(std::string(reinterpret_cast<const char *>(data) + 1,len - 1)); // throws on invalid JSON
|
||||
if (req.is_object()) {
|
||||
const unsigned int rvMaj = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR],0);
|
||||
const unsigned int rvMin = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR],0);
|
||||
const unsigned int rvRev = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION],0);
|
||||
const unsigned int rvBld = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD],0);
|
||||
const unsigned int rvPlatform = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_PLATFORM],0);
|
||||
const unsigned int rvArch = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE],0);
|
||||
const unsigned int rvVendor = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VENDOR],0);
|
||||
const std::string rvChannel(OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_CHANNEL],""));
|
||||
|
||||
if (v == VERB_GET_LATEST) {
|
||||
|
||||
if (_dist.size() > 0) {
|
||||
const nlohmann::json *latest = (const nlohmann::json *)0;
|
||||
const std::string expectedSigner = OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_EXPECT_SIGNED_BY],"");
|
||||
unsigned int bestVMaj = rvMaj;
|
||||
unsigned int bestVMin = rvMin;
|
||||
unsigned int bestVRev = rvRev;
|
||||
unsigned int bestVBld = rvBld;
|
||||
for(std::map< Array<uint8_t,16>,_D >::const_iterator d(_dist.begin());d!=_dist.end();++d) {
|
||||
if ((OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_PLATFORM],0) == rvPlatform)&&
|
||||
(OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE],0) == rvArch)&&
|
||||
(OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VENDOR],0) == rvVendor)&&
|
||||
(OSUtils::jsonString(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_CHANNEL],"") == rvChannel)&&
|
||||
(OSUtils::jsonString(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNED_BY],"") == expectedSigner)) {
|
||||
const unsigned int dvMaj = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR],0);
|
||||
const unsigned int dvMin = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR],0);
|
||||
const unsigned int dvRev = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION],0);
|
||||
const unsigned int dvBld = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD],0);
|
||||
if (Utils::compareVersion(dvMaj,dvMin,dvRev,dvBld,bestVMaj,bestVMin,bestVRev,bestVBld) > 0) {
|
||||
latest = &(d->second.meta);
|
||||
bestVMaj = dvMaj;
|
||||
bestVMin = dvMin;
|
||||
bestVRev = dvRev;
|
||||
bestVBld = dvBld;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (latest) {
|
||||
std::string lj;
|
||||
lj.push_back((char)VERB_LATEST);
|
||||
lj.append(OSUtils::jsonDump(*latest));
|
||||
_node.sendUserMessage(origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,lj.data(),(unsigned int)lj.length());
|
||||
if (_distLog) {
|
||||
fprintf(_distLog,"%.10llx GET_LATEST %u.%u.%u_%u platform %u arch %u vendor %u channel %s -> LATEST %u.%u.%u_%u" ZT_EOL_S,(unsigned long long)origin,rvMaj,rvMin,rvRev,rvBld,rvPlatform,rvArch,rvVendor,rvChannel.c_str(),bestVMaj,bestVMin,bestVRev,bestVBld);
|
||||
fflush(_distLog);
|
||||
}
|
||||
}
|
||||
} // else no reply, since we have nothing to distribute
|
||||
|
||||
} else { // VERB_LATEST
|
||||
|
||||
if ((origin == ZT_SOFTWARE_UPDATE_SERVICE)&&
|
||||
(Utils::compareVersion(rvMaj,rvMin,rvRev,rvBld,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION,ZEROTIER_ONE_VERSION_BUILD) > 0)&&
|
||||
(OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNED_BY],"") == ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY)) {
|
||||
const unsigned long len = (unsigned long)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE],0);
|
||||
const std::string hash = OSUtils::jsonBinFromHex(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH]);
|
||||
if ((len <= ZT_SOFTWARE_UPDATE_MAX_SIZE)&&(hash.length() >= 16)) {
|
||||
if (_latestMeta != req) {
|
||||
_latestMeta = req;
|
||||
_latestValid = false;
|
||||
|
||||
OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_META_FILENAME).c_str());
|
||||
OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str());
|
||||
|
||||
_download = std::string();
|
||||
memcpy(_downloadHashPrefix.data,hash.data(),16);
|
||||
_downloadLength = len;
|
||||
}
|
||||
|
||||
if ((_downloadLength > 0)&&(_download.length() < _downloadLength)) {
|
||||
Buffer<128> gd;
|
||||
gd.append((uint8_t)VERB_GET_DATA);
|
||||
gd.append(_downloadHashPrefix.data,16);
|
||||
gd.append((uint32_t)_download.length());
|
||||
_node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size());
|
||||
//printf(">> GET_DATA @%u\n",(unsigned int)_download.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} break;
|
||||
|
||||
case VERB_GET_DATA:
|
||||
if ((len >= 21)&&(_dist.size() > 0)) {
|
||||
unsigned long idx = (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 17) << 24;
|
||||
idx |= (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 18) << 16;
|
||||
idx |= (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 19) << 8;
|
||||
idx |= (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 20);
|
||||
//printf("<< GET_DATA @%u from %.10llx for %s\n",(unsigned int)idx,origin,Utils::hex(reinterpret_cast<const uint8_t *>(data) + 1,16).c_str());
|
||||
std::map< Array<uint8_t,16>,_D >::iterator d(_dist.find(Array<uint8_t,16>(reinterpret_cast<const uint8_t *>(data) + 1)));
|
||||
if ((d != _dist.end())&&(idx < (unsigned long)d->second.bin.length())) {
|
||||
Buffer<ZT_SOFTWARE_UPDATE_CHUNK_SIZE + 128> buf;
|
||||
buf.append((uint8_t)VERB_DATA);
|
||||
buf.append(reinterpret_cast<const uint8_t *>(data) + 1,16);
|
||||
buf.append((uint32_t)idx);
|
||||
buf.append(d->second.bin.data() + idx,std::min((unsigned long)ZT_SOFTWARE_UPDATE_CHUNK_SIZE,(unsigned long)(d->second.bin.length() - idx)));
|
||||
_node.sendUserMessage(origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,buf.data(),buf.size());
|
||||
//printf(">> DATA @%u\n",(unsigned int)idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case VERB_DATA:
|
||||
if ((len >= 21)&&(_downloadLength > 0)&&(!memcmp(_downloadHashPrefix.data,reinterpret_cast<const uint8_t *>(data) + 1,16))) {
|
||||
unsigned long idx = (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 17) << 24;
|
||||
idx |= (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 18) << 16;
|
||||
idx |= (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 19) << 8;
|
||||
idx |= (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 20);
|
||||
//printf("<< DATA @%u / %u bytes (we now have %u bytes)\n",(unsigned int)idx,(unsigned int)(len - 21),(unsigned int)_download.length());
|
||||
if (idx == (unsigned long)_download.length()) {
|
||||
_download.append(reinterpret_cast<const char *>(data) + 21,len - 21);
|
||||
if (_download.length() < _downloadLength) {
|
||||
Buffer<128> gd;
|
||||
gd.append((uint8_t)VERB_GET_DATA);
|
||||
gd.append(_downloadHashPrefix.data,16);
|
||||
gd.append((uint32_t)_download.length());
|
||||
_node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size());
|
||||
//printf(">> GET_DATA @%u\n",(unsigned int)_download.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (_distLog) {
|
||||
fprintf(_distLog,"%.10llx WARNING: bad update message verb==%u length==%u (unrecognized verb)" ZT_EOL_S,origin,(unsigned int)v,len);
|
||||
fflush(_distLog);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch ( ... ) {
|
||||
if (_distLog) {
|
||||
fprintf(_distLog,"%.10llx WARNING: bad update message verb==%u length==%u (unexpected exception, likely invalid JSON)" ZT_EOL_S,origin,(unsigned int)v,len);
|
||||
fflush(_distLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SoftwareUpdater::check(const uint64_t now)
|
||||
{
|
||||
if ((now - _lastCheckTime) >= ZT_SOFTWARE_UPDATE_CHECK_PERIOD) {
|
||||
_lastCheckTime = now;
|
||||
char tmp[512];
|
||||
const unsigned int len = Utils::snprintf(tmp,sizeof(tmp),
|
||||
"%c{\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR "\":%d,"
|
||||
"\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR "\":%d,"
|
||||
"\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION "\":%d,"
|
||||
"\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD "\":%d,"
|
||||
"\"" ZT_SOFTWARE_UPDATE_JSON_EXPECT_SIGNED_BY "\":\"%s\","
|
||||
"\"" ZT_SOFTWARE_UPDATE_JSON_PLATFORM "\":%d,"
|
||||
"\"" ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE "\":%d,"
|
||||
"\"" ZT_SOFTWARE_UPDATE_JSON_VENDOR "\":%d,"
|
||||
"\"" ZT_SOFTWARE_UPDATE_JSON_CHANNEL "\":\"%s\"}",
|
||||
(char)VERB_GET_LATEST,
|
||||
ZEROTIER_ONE_VERSION_MAJOR,
|
||||
ZEROTIER_ONE_VERSION_MINOR,
|
||||
ZEROTIER_ONE_VERSION_REVISION,
|
||||
ZEROTIER_ONE_VERSION_BUILD,
|
||||
ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY,
|
||||
ZT_BUILD_PLATFORM,
|
||||
ZT_BUILD_ARCHITECTURE,
|
||||
(int)ZT_VENDOR_ZEROTIER,
|
||||
_channel.c_str());
|
||||
_node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,tmp,len);
|
||||
//printf(">> GET_LATEST\n");
|
||||
}
|
||||
|
||||
if (_latestValid)
|
||||
return true;
|
||||
|
||||
if (_downloadLength > 0) {
|
||||
if (_download.length() >= _downloadLength) {
|
||||
// This is the very important security validation part that makes sure
|
||||
// this software update doesn't have cooties.
|
||||
|
||||
const std::string metaPath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_META_FILENAME);
|
||||
const std::string binPath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME);
|
||||
|
||||
try {
|
||||
// (1) Check the hash itself to make sure the image is basically okay
|
||||
uint8_t sha512[ZT_SHA512_DIGEST_LEN];
|
||||
SHA512::hash(sha512,_download.data(),(unsigned int)_download.length());
|
||||
if (Utils::hex(sha512,ZT_SHA512_DIGEST_LEN) == OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH],"")) {
|
||||
// (2) Check signature by signing authority
|
||||
const std::string sig(OSUtils::jsonBinFromHex(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE]));
|
||||
if (Identity(ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY).verify(_download.data(),(unsigned int)_download.length(),sig.data(),(unsigned int)sig.length())) {
|
||||
// (3) Try to save file, and if so we are good.
|
||||
if (OSUtils::writeFile(metaPath.c_str(),OSUtils::jsonDump(_latestMeta)) && OSUtils::writeFile(binPath.c_str(),_download)) {
|
||||
OSUtils::lockDownFile(metaPath.c_str(),false);
|
||||
OSUtils::lockDownFile(binPath.c_str(),false);
|
||||
_latestValid = true;
|
||||
//printf("VALID UPDATE\n%s\n",OSUtils::jsonDump(_latestMeta).c_str());
|
||||
_download = std::string();
|
||||
_downloadLength = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {} // any exception equals verification failure
|
||||
|
||||
// If we get here, checks failed.
|
||||
//printf("INVALID UPDATE (!!!)\n%s\n",OSUtils::jsonDump(_latestMeta).c_str());
|
||||
OSUtils::rm(metaPath.c_str());
|
||||
OSUtils::rm(binPath.c_str());
|
||||
_latestMeta = nlohmann::json();
|
||||
_latestValid = false;
|
||||
_download = std::string();
|
||||
_downloadLength = 0;
|
||||
} else {
|
||||
Buffer<128> gd;
|
||||
gd.append((uint8_t)VERB_GET_DATA);
|
||||
gd.append(_downloadHashPrefix.data,16);
|
||||
gd.append((uint32_t)_download.length());
|
||||
_node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size());
|
||||
//printf(">> GET_DATA @%u\n",(unsigned int)_download.length());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SoftwareUpdater::apply()
|
||||
{
|
||||
std::string updatePath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME);
|
||||
if ((_latestMeta.is_object())&&(_latestValid)&&(OSUtils::fileExists(updatePath.c_str(),false))) {
|
||||
#ifdef __WINDOWS__
|
||||
std::string cmdArgs(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS],""));
|
||||
if (cmdArgs.length() > 0) {
|
||||
updatePath.push_back(' ');
|
||||
updatePath.append(cmdArgs);
|
||||
}
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi;
|
||||
memset(&si,0,sizeof(si));
|
||||
memset(&pi,0,sizeof(pi));
|
||||
CreateProcessA(NULL,const_cast<LPSTR>(updatePath.c_str()),NULL,NULL,FALSE,CREATE_NO_WINDOW|CREATE_NEW_PROCESS_GROUP,NULL,NULL,&si,&pi);
|
||||
// Windows doesn't exit here -- updater will stop the service during update, etc. -- but we do want to stop multiple runs from happening
|
||||
_latestMeta = nlohmann::json();
|
||||
_latestValid = false;
|
||||
#else
|
||||
char *argv[256];
|
||||
unsigned long ac = 0;
|
||||
argv[ac++] = const_cast<char *>(updatePath.c_str());
|
||||
const std::vector<std::string> argsSplit(OSUtils::split(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS],"").c_str()," ","\\","\""));
|
||||
for(std::vector<std::string>::const_iterator a(argsSplit.begin());a!=argsSplit.end();++a) {
|
||||
argv[ac] = const_cast<char *>(a->c_str());
|
||||
if (++ac == 255) break;
|
||||
}
|
||||
argv[ac] = (char *)0;
|
||||
chmod(updatePath.c_str(),0700);
|
||||
|
||||
// Close all open file descriptors except stdout/stderr/etc.
|
||||
int minMyFd = STDIN_FILENO;
|
||||
if (STDOUT_FILENO > minMyFd) minMyFd = STDOUT_FILENO;
|
||||
if (STDERR_FILENO > minMyFd) minMyFd = STDERR_FILENO;
|
||||
++minMyFd;
|
||||
#ifdef _SC_OPEN_MAX
|
||||
int maxMyFd = (int)sysconf(_SC_OPEN_MAX);
|
||||
if (maxMyFd <= minMyFd)
|
||||
maxMyFd = 65536;
|
||||
#else
|
||||
int maxMyFd = 65536;
|
||||
#endif
|
||||
while (minMyFd < maxMyFd)
|
||||
close(minMyFd++);
|
||||
|
||||
execv(updatePath.c_str(),argv);
|
||||
fprintf(stderr,"FATAL: unable to execute software update binary at %s\n",updatePath.c_str());
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
215
zerotierone/service/SoftwareUpdater.hpp
Normal file
215
zerotierone/service/SoftwareUpdater.hpp
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_SOFTWAREUPDATER_HPP
|
||||
#define ZT_SOFTWAREUPDATER_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "../include/ZeroTierOne.h"
|
||||
|
||||
#include "../node/Identity.hpp"
|
||||
#include "../node/Array.hpp"
|
||||
#include "../node/Packet.hpp"
|
||||
|
||||
#include "../ext/json/json.hpp"
|
||||
|
||||
/**
|
||||
* VERB_USER_MESSAGE type ID for software update messages
|
||||
*/
|
||||
#define ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE 100
|
||||
|
||||
/**
|
||||
* ZeroTier address of node that provides software updates
|
||||
*/
|
||||
#define ZT_SOFTWARE_UPDATE_SERVICE 0xb1d366e81fULL
|
||||
|
||||
/**
|
||||
* ZeroTier identity that must be used to sign software updates
|
||||
*
|
||||
* df24360f3e - update-signing-key-0010 generated Fri Jan 13th, 2017 at 4:05pm PST
|
||||
*/
|
||||
#define ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY "df24360f3e:0:06072642959c8dfb68312904d74d90197c8a7692697caa1b3fd769eca714f4370fab462fcee6ebcb5fffb63bc5af81f28a2514b2cd68daabb42f7352c06f21db"
|
||||
|
||||
/**
|
||||
* Chunk size for in-band downloads (can be changed, designed to always fit in one UDP packet easily)
|
||||
*/
|
||||
#define ZT_SOFTWARE_UPDATE_CHUNK_SIZE (ZT_PROTO_MAX_PACKET_LENGTH - 128)
|
||||
|
||||
/**
|
||||
* Sanity limit for the size of an update binary image
|
||||
*/
|
||||
#define ZT_SOFTWARE_UPDATE_MAX_SIZE (1024 * 1024 * 256)
|
||||
|
||||
/**
|
||||
* How often (ms) do we check?
|
||||
*/
|
||||
//#define ZT_SOFTWARE_UPDATE_CHECK_PERIOD (60 * 60 * 1000)
|
||||
#define ZT_SOFTWARE_UPDATE_CHECK_PERIOD 5000
|
||||
|
||||
/**
|
||||
* Default update channel
|
||||
*/
|
||||
#define ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL "release"
|
||||
|
||||
/**
|
||||
* Filename for latest update's meta JSON
|
||||
*/
|
||||
#define ZT_SOFTWARE_UPDATE_META_FILENAME "latest-update.json"
|
||||
|
||||
/**
|
||||
* Filename for latest update's binary image
|
||||
*/
|
||||
#define ZT_SOFTWARE_UPDATE_BIN_FILENAME "latest-update.exe"
|
||||
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR "versionMajor"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR "versionMinor"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION "versionRev"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD "versionBuild"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_PLATFORM "platform"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE "arch"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_VENDOR "vendor"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_CHANNEL "channel"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_EXPECT_SIGNED_BY "expectedSigner"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNED_BY "updateSigner"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE "updateSig"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH "updateHash"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE "updateSize"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS "updateExecArgs"
|
||||
#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_URL "updateUrl"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class Node;
|
||||
|
||||
/**
|
||||
* This class handles retrieving and executing updates, or serving them
|
||||
*/
|
||||
class SoftwareUpdater
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Each message begins with an 8-bit message verb
|
||||
*/
|
||||
enum MessageVerb
|
||||
{
|
||||
/**
|
||||
* Payload: JSON containing current system platform, version, etc.
|
||||
*/
|
||||
VERB_GET_LATEST = 1,
|
||||
|
||||
/**
|
||||
* Payload: JSON describing latest update for this target. (No response is sent if there is none.)
|
||||
*/
|
||||
VERB_LATEST = 2,
|
||||
|
||||
/**
|
||||
* Payload:
|
||||
* <[16] first 128 bits of hash of data object>
|
||||
* <[4] 32-bit index of chunk to get>
|
||||
*/
|
||||
VERB_GET_DATA = 3,
|
||||
|
||||
/**
|
||||
* Payload:
|
||||
* <[16] first 128 bits of hash of data object>
|
||||
* <[4] 32-bit index of chunk>
|
||||
* <[...] chunk data>
|
||||
*/
|
||||
VERB_DATA = 4
|
||||
};
|
||||
|
||||
SoftwareUpdater(Node &node,const std::string &homePath);
|
||||
~SoftwareUpdater();
|
||||
|
||||
/**
|
||||
* Set whether or not we will distribute updates
|
||||
*
|
||||
* @param distribute If true, scan update-dist.d now and distribute updates found there -- if false, clear and stop distributing
|
||||
*/
|
||||
void setUpdateDistribution(bool distribute);
|
||||
|
||||
/**
|
||||
* Handle a software update user message
|
||||
*
|
||||
* @param origin ZeroTier address of message origin
|
||||
* @param data Message payload
|
||||
* @param len Length of message
|
||||
*/
|
||||
void handleSoftwareUpdateUserMessage(uint64_t origin,const void *data,unsigned int len);
|
||||
|
||||
/**
|
||||
* Check for updates and do other update-related housekeeping
|
||||
*
|
||||
* It should be called about every 10 seconds.
|
||||
*
|
||||
* @return True if we've downloaded and verified an update
|
||||
*/
|
||||
bool check(const uint64_t now);
|
||||
|
||||
/**
|
||||
* @return Meta-data for downloaded update or NULL if none
|
||||
*/
|
||||
inline const nlohmann::json &pending() const { return _latestMeta; }
|
||||
|
||||
/**
|
||||
* Apply any ready update now
|
||||
*
|
||||
* Depending on the platform this function may never return and may forcibly
|
||||
* exit the process. It does nothing if no update is ready.
|
||||
*/
|
||||
void apply();
|
||||
|
||||
/**
|
||||
* Set software update channel
|
||||
*
|
||||
* @param channel 'release', 'beta', etc.
|
||||
*/
|
||||
inline void setChannel(const std::string &channel) { _channel = channel; }
|
||||
|
||||
private:
|
||||
Node &_node;
|
||||
uint64_t _lastCheckTime;
|
||||
std::string _homePath;
|
||||
std::string _channel;
|
||||
FILE *_distLog;
|
||||
|
||||
// Offered software updates if we are an update host (we have update-dist.d and update hosting is enabled)
|
||||
struct _D
|
||||
{
|
||||
nlohmann::json meta;
|
||||
std::string bin;
|
||||
};
|
||||
std::map< Array<uint8_t,16>,_D > _dist; // key is first 16 bytes of hash
|
||||
|
||||
nlohmann::json _latestMeta;
|
||||
bool _latestValid;
|
||||
|
||||
std::string _download;
|
||||
Array<uint8_t,16> _downloadHashPrefix;
|
||||
unsigned long _downloadLength;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
103
zerotierone/windows/WinUI/AboutView.xaml
Normal file
103
zerotierone/windows/WinUI/AboutView.xaml
Normal file
@@ -0,0 +1,103 @@
|
||||
<Window x:Class="WinUI.AboutView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:WinUI"
|
||||
mc:Ignorable="d"
|
||||
Title="AboutView" Height="460" Width="300" Icon="ZeroTierIcon.ico">
|
||||
<Grid>
|
||||
<Image x:Name="image" HorizontalAlignment="Center" Height="100" Margin="0,10,0,0" VerticalAlignment="Top" Width="100" Source="ZeroTierIcon.ico"/>
|
||||
<RichTextBox x:Name="richTextBox" HorizontalAlignment="Left" Height="307" Margin="10,115,0,0" VerticalAlignment="Top" Width="275" IsReadOnly="True" IsDocumentEnabled="True" BorderThickness="0">
|
||||
<RichTextBox.Resources>
|
||||
<Style TargetType="Hyperlink">
|
||||
<Setter Property="Cursor" Value="Hand" />
|
||||
</Style>
|
||||
</RichTextBox.Resources>
|
||||
<FlowDocument>
|
||||
<Paragraph>
|
||||
<Span FontWeight="Bold" FontSize="18" FontFamily="HelveticaNeue">
|
||||
<Run Text="Getting Started"/>
|
||||
</Span>
|
||||
<Span FontWeight="Bold" FontSize="12" FontFamily="HelveticaNeue">
|
||||
<LineBreak/>
|
||||
</Span>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run/>
|
||||
</Span>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run Text="Getting started is simple. Simply click "/>
|
||||
</Span>
|
||||
<Span FontSize="12" FontFamily="Menlo-Regular">
|
||||
<Run Text="Join Network"/>
|
||||
</Span>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run Text=" from the ZeroTier status bar menu. To join the public network "Earth", enter "/>
|
||||
</Span>
|
||||
<Span FontSize="12" FontFamily="Menlo-Regular">
|
||||
<Run Text="8056c2e21c000001"/>
|
||||
</Span>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run Text=" and click the Join button. Once connected, you'll be able to navigate to "/>
|
||||
</Span>
|
||||
<Hyperlink NavigateUri="http://earth.zerotier.net/" RequestNavigate="Hyperlink_MouseLeftButtonDown">
|
||||
<Span Foreground="#FF0000E9" FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run Text="earth.zerotier.net"/>
|
||||
</Span>
|
||||
</Hyperlink>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run Text="."/>
|
||||
</Span>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run/>
|
||||
<LineBreak/>
|
||||
</Span>
|
||||
<Span FontWeight="Bold" FontSize="18" FontFamily="HelveticaNeue">
|
||||
<Run Text="Create a Network"/>
|
||||
</Span>
|
||||
<Span FontWeight="Bold" FontSize="12" FontFamily="HelveticaNeue">
|
||||
<LineBreak/>
|
||||
</Span>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run/>
|
||||
</Span>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run Text="Visit "/>
|
||||
</Span>
|
||||
<Hyperlink NavigateUri="http://my.zerotier.com/" RequestNavigate="Hyperlink_MouseLeftButtonDown">
|
||||
<Span Foreground="#FF0000E9" FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run Text="my.zerotier.com"/>
|
||||
</Span>
|
||||
</Hyperlink>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run Text=" to create and manage your own virtual networks."/>
|
||||
</Span>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<LineBreak/>
|
||||
<Run/>
|
||||
</Span>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run Text="For more information, visit "/>
|
||||
</Span>
|
||||
<Hyperlink NavigateUri="http://www.zerotier.com/" RequestNavigate="Hyperlink_MouseLeftButtonDown">
|
||||
<Span Foreground="#FF0000E9" FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run Text="zerotier.com"/>
|
||||
</Span>
|
||||
</Hyperlink>
|
||||
<Span FontSize="12" FontFamily="HelveticaNeue">
|
||||
<Run Text="."/>
|
||||
</Span>
|
||||
</Paragraph>
|
||||
</FlowDocument>
|
||||
</RichTextBox>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
||||
35
zerotierone/windows/WinUI/AboutView.xaml.cs
Normal file
35
zerotierone/windows/WinUI/AboutView.xaml.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace WinUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for AboutView.xaml
|
||||
/// </summary>
|
||||
public partial class AboutView : Window
|
||||
{
|
||||
public AboutView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Hyperlink_MouseLeftButtonDown(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
var hyperlink = (Hyperlink)sender;
|
||||
Process.Start(hyperlink.NavigateUri.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
16
zerotierone/windows/WinUI/JoinNetworkView.xaml
Normal file
16
zerotierone/windows/WinUI/JoinNetworkView.xaml
Normal file
@@ -0,0 +1,16 @@
|
||||
<Window x:Class="WinUI.JoinNetworkView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:WinUI"
|
||||
mc:Ignorable="d"
|
||||
Title="Join a Network" SizeToContent="WidthAndHeight" Height="Auto" Width="Auto" Icon="ZeroTierIcon.ico">
|
||||
<Grid HorizontalAlignment="Left" Margin="0,0,0,0" Width="315">
|
||||
<TextBox x:Name="joinNetworkBox" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="291" PreviewTextInput="joinNetworkBox_OnTextEntered" PreviewKeyDown="joinNetworkBox_OnKeyDown"/>
|
||||
<CheckBox x:Name="allowManagedCheckbox" Content="Allow Managed" HorizontalAlignment="Left" Margin="10,38,0,0" VerticalAlignment="Top" IsChecked="True"/>
|
||||
<CheckBox x:Name="allowGlobalCheckbox" Content="Allow Global" HorizontalAlignment="Left" Margin="118,38,0,0" VerticalAlignment="Top"/>
|
||||
<CheckBox x:Name="allowDefaultCheckbox" Content="Allow Default" HorizontalAlignment="Left" Margin="210,38,-6,0" VerticalAlignment="Top"/>
|
||||
<Button x:Name="joinButton" Content="Join" HorizontalAlignment="Left" Margin="226,58,0,10" Background="#FFFFB354" VerticalAlignment="Top" Width="75" Click="joinButton_Click" IsEnabled="False"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
126
zerotierone/windows/WinUI/JoinNetworkView.xaml.cs
Normal file
126
zerotierone/windows/WinUI/JoinNetworkView.xaml.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace WinUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for JoinNetworkView.xaml
|
||||
/// </summary>
|
||||
public partial class JoinNetworkView : Window
|
||||
{
|
||||
Regex charRegex = new Regex("[0-9a-fxA-FX]");
|
||||
Regex wholeStringRegex = new Regex("^[0-9a-fxA-FX]+$");
|
||||
|
||||
public JoinNetworkView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
DataObject.AddPastingHandler(joinNetworkBox, onPaste);
|
||||
DataObject.AddCopyingHandler(joinNetworkBox, onCopyCut);
|
||||
}
|
||||
|
||||
private void joinNetworkBox_OnTextEntered(object sender, TextCompositionEventArgs e)
|
||||
{
|
||||
e.Handled = !charRegex.IsMatch(e.Text);
|
||||
|
||||
if ( (joinNetworkBox.Text.Length + e.Text.Length) == 16)
|
||||
{
|
||||
joinButton.IsEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
joinButton.IsEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void joinNetworkBox_OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||
{
|
||||
if (e.Key == Key.X && joinNetworkBox.IsSelectionActive)
|
||||
{
|
||||
// handle ctrl-x removing characters
|
||||
joinButton.IsEnabled = false;
|
||||
}
|
||||
}
|
||||
else if (e.Key == Key.Delete || e.Key == Key.Back)
|
||||
{
|
||||
if ((joinNetworkBox.Text.Length - 1) == 16)
|
||||
{
|
||||
joinButton.IsEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
joinButton.IsEnabled = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((joinNetworkBox.Text.Length + 1) > 16)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onPaste(object sender, DataObjectPastingEventArgs e)
|
||||
{
|
||||
var isText = e.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true);
|
||||
if (!isText)
|
||||
{
|
||||
joinButton.IsEnabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var text = e.SourceDataObject.GetData(DataFormats.UnicodeText) as string;
|
||||
|
||||
if (!wholeStringRegex.IsMatch(text))
|
||||
{
|
||||
e.Handled = true;
|
||||
e.CancelCommand();
|
||||
}
|
||||
|
||||
if (text.Length == 16 || (joinNetworkBox.Text.Length + text.Length) == 16)
|
||||
{
|
||||
joinButton.IsEnabled = true;
|
||||
}
|
||||
else if (text.Length > 16 || (joinNetworkBox.Text.Length + text.Length) > 16)
|
||||
{
|
||||
e.Handled = true;
|
||||
e.CancelCommand();
|
||||
}
|
||||
else
|
||||
{
|
||||
joinButton.IsEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void onCopyCut(object sender, DataObjectCopyingEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void joinButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
bool allowDefault = allowDefaultCheckbox.IsChecked.Value;
|
||||
bool allowGlobal = allowGlobalCheckbox.IsChecked.Value;
|
||||
bool allowManaged = allowManagedCheckbox.IsChecked.Value;
|
||||
|
||||
APIHandler.Instance.JoinNetwork(joinNetworkBox.Text, allowManaged, allowGlobal, allowDefault);
|
||||
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
88
zerotierone/windows/WinUI/NetworkListView.xaml
Normal file
88
zerotierone/windows/WinUI/NetworkListView.xaml
Normal file
@@ -0,0 +1,88 @@
|
||||
<Window
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:WinUI"
|
||||
mc:Ignorable="d" x:Class="WinUI.NetworkListView"
|
||||
Title="ZeroTier One" SizeToContent="Width" Height="500" Width="Auto" Icon="ZeroTierIcon.ico">
|
||||
|
||||
<Window.Resources>
|
||||
<SolidColorBrush x:Key="GreenBrush" Color="#ff91a2a3"/>
|
||||
|
||||
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
|
||||
|
||||
<SolidColorBrush x:Key="GreenDisabledBrush" Color="#FF234447" />
|
||||
|
||||
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
|
||||
|
||||
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
|
||||
|
||||
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
|
||||
|
||||
<Style TargetType="{x:Type DataGrid}">
|
||||
<Setter Property="Background" Value="#FFF" />
|
||||
<Setter Property="AlternationCount" Value="2" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type DataGridRow}">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
|
||||
<Setter Property="Background" Value="#EEE"></Setter>
|
||||
</Trigger>
|
||||
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
|
||||
<Setter Property="Background" Value="#FFF"></Setter>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type TabItem}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type TabItem}">
|
||||
<Grid>
|
||||
<Border
|
||||
Name="Border"
|
||||
Margin="0,0,-4,0"
|
||||
Background="{StaticResource GreenBrush}"
|
||||
BorderBrush="{StaticResource SolidBorderBrush}"
|
||||
BorderThickness="1,1,1,1"
|
||||
CornerRadius="2,12,0,0" >
|
||||
<ContentPresenter x:Name="ContentSite"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
ContentSource="Header"
|
||||
Margin="12,2,12,2"
|
||||
RecognizesAccessKey="True"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Panel.ZIndex" Value="100" />
|
||||
<Setter TargetName="Border" Property="Background" Value="{StaticResource GreenDisabledBrush}" />
|
||||
<Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
|
||||
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<DockPanel>
|
||||
<Grid Background="LightGray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<local:NetworksPage x:Name="networksPage" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="0" Grid.Row="0" Margin="0,0,0,0"/>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
85
zerotierone/windows/WinUI/NetworkListView.xaml.cs
Normal file
85
zerotierone/windows/WinUI/NetworkListView.xaml.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Timers;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using System.Windows.Threading;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace WinUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class NetworkListView : Window
|
||||
{
|
||||
Regex charRegex = new Regex("[0-9a-fxA-FX]");
|
||||
Regex wholeStringRegex = new Regex("^[0-9a-fxA-FX]+$");
|
||||
|
||||
public NetworkListView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Closed += onClosed;
|
||||
|
||||
NetworkMonitor.Instance.SubscribeNetworkUpdates(updateNetworks);
|
||||
}
|
||||
|
||||
~NetworkListView()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
e.Cancel = true;
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void onClosed(object sender, System.EventArgs e)
|
||||
{
|
||||
NetworkMonitor.Instance.UnsubscribeNetworkUpdates(updateNetworks);
|
||||
}
|
||||
|
||||
private void updateNetworks(List<ZeroTierNetwork> networks)
|
||||
{
|
||||
if (networks != null)
|
||||
{
|
||||
networksPage.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
|
||||
{
|
||||
networksPage.setNetworks(networks);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkEntered(object sender, TextCompositionEventArgs e)
|
||||
{
|
||||
e.Handled = !charRegex.IsMatch(e.Text);
|
||||
}
|
||||
|
||||
private void OnPaste(object sender, DataObjectPastingEventArgs e)
|
||||
{
|
||||
var isText = e.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true);
|
||||
if (!isText) return;
|
||||
|
||||
var text = e.SourceDataObject.GetData(DataFormats.UnicodeText) as string;
|
||||
|
||||
if (!wholeStringRegex.IsMatch(text))
|
||||
{
|
||||
e.CancelCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
197
zerotierone/windows/WinUI/NetworkMonitor.cs
Normal file
197
zerotierone/windows/WinUI/NetworkMonitor.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WinUI
|
||||
{
|
||||
class NetworkMonitor
|
||||
{
|
||||
public delegate void NetworkListCallback(List<ZeroTierNetwork> networks);
|
||||
public delegate void StatusCallback(ZeroTierStatus status);
|
||||
|
||||
private Thread runThread;
|
||||
private NetworkListCallback _nwCb;
|
||||
private StatusCallback _stCb;
|
||||
|
||||
|
||||
private List<ZeroTierNetwork> _knownNetworks = new List<ZeroTierNetwork>();
|
||||
|
||||
private static NetworkMonitor instance;
|
||||
private static object syncRoot = new object();
|
||||
|
||||
public static NetworkMonitor Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new NetworkMonitor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
private NetworkMonitor()
|
||||
{
|
||||
runThread = new Thread(new ThreadStart(run));
|
||||
loadNetworks();
|
||||
|
||||
runThread.Start();
|
||||
}
|
||||
|
||||
~NetworkMonitor()
|
||||
{
|
||||
runThread.Interrupt();
|
||||
}
|
||||
|
||||
private void loadNetworks()
|
||||
{
|
||||
String dataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\ZeroTier\\One";
|
||||
String dataFile = Path.Combine(dataPath, "networks.dat");
|
||||
|
||||
if (File.Exists(dataFile))
|
||||
{
|
||||
List<ZeroTierNetwork> netList;
|
||||
|
||||
using (Stream stream = File.Open(dataFile, FileMode.Open))
|
||||
{
|
||||
var bformatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
|
||||
netList = (List<ZeroTierNetwork>)bformatter.Deserialize(stream);
|
||||
stream.Close();
|
||||
}
|
||||
|
||||
lock (_knownNetworks)
|
||||
{
|
||||
_knownNetworks = netList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeNetworks()
|
||||
{
|
||||
String dataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\ZeroTier\\One";
|
||||
String dataFile = Path.Combine(dataPath, "networks.dat");
|
||||
|
||||
if (!Directory.Exists(dataPath))
|
||||
{
|
||||
Directory.CreateDirectory(dataPath);
|
||||
}
|
||||
|
||||
using (Stream stream = File.Open(dataFile, FileMode.OpenOrCreate))
|
||||
{
|
||||
lock (_knownNetworks)
|
||||
{
|
||||
var bformatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
|
||||
bformatter.Serialize(stream, _knownNetworks);
|
||||
stream.Flush();
|
||||
stream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void apiNetworkCallback(List<ZeroTierNetwork> networks)
|
||||
{
|
||||
lock (_knownNetworks)
|
||||
{
|
||||
_knownNetworks = _knownNetworks.Union(networks, new NetworkEqualityComparer()).ToList();
|
||||
|
||||
foreach (ZeroTierNetwork n in _knownNetworks)
|
||||
{
|
||||
if (networks.Contains(n))
|
||||
{
|
||||
n.IsConnected = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
n.IsConnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
_knownNetworks.Sort();
|
||||
_nwCb(_knownNetworks);
|
||||
}
|
||||
|
||||
writeNetworks();
|
||||
}
|
||||
|
||||
private void apiStatusCallback(ZeroTierStatus status)
|
||||
{
|
||||
_stCb(status);
|
||||
}
|
||||
|
||||
private void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (runThread.IsAlive)
|
||||
{
|
||||
APIHandler handler = APIHandler.Instance;
|
||||
|
||||
if (handler != null)
|
||||
{
|
||||
handler.GetNetworks(apiNetworkCallback);
|
||||
handler.GetStatus(apiStatusCallback);
|
||||
}
|
||||
|
||||
Thread.Sleep(2000);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Monitor Thread Ended");
|
||||
}
|
||||
}
|
||||
|
||||
public void SubscribeStatusUpdates(StatusCallback cb)
|
||||
{
|
||||
_stCb += cb;
|
||||
}
|
||||
|
||||
public void UnsubscribeStatusUpdates(StatusCallback cb)
|
||||
{
|
||||
_stCb -= cb;
|
||||
}
|
||||
|
||||
public void SubscribeNetworkUpdates(NetworkListCallback cb)
|
||||
{
|
||||
_nwCb += cb;
|
||||
}
|
||||
|
||||
public void UnsubscribeNetworkUpdates(NetworkListCallback cb)
|
||||
{
|
||||
_nwCb -= cb;
|
||||
}
|
||||
|
||||
public void RemoveNetwork(String networkID)
|
||||
{
|
||||
lock(_knownNetworks)
|
||||
{
|
||||
foreach (ZeroTierNetwork n in _knownNetworks)
|
||||
{
|
||||
if (n.NetworkId.Equals(networkID))
|
||||
{
|
||||
_knownNetworks.Remove(n);
|
||||
writeNetworks();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void StopMonitor()
|
||||
{
|
||||
runThread.Abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
zerotierone/windows/WinUI/NetworkRoute.cs
Normal file
42
zerotierone/windows/WinUI/NetworkRoute.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace WinUI
|
||||
{
|
||||
[Serializable]
|
||||
public class NetworkRoute : ISerializable
|
||||
{
|
||||
protected NetworkRoute(SerializationInfo info, StreamingContext ctx)
|
||||
{
|
||||
Target = info.GetString("target");
|
||||
Via = info.GetString("via");
|
||||
Flags = info.GetInt32("flags");
|
||||
Metric = info.GetInt32("metric");
|
||||
}
|
||||
|
||||
public virtual void GetObjectData(SerializationInfo info, StreamingContext ctx)
|
||||
{
|
||||
info.AddValue("target", Target);
|
||||
info.AddValue("via", Via);
|
||||
info.AddValue("flags", Flags);
|
||||
info.AddValue("metric", Metric);
|
||||
}
|
||||
|
||||
[JsonProperty("target")]
|
||||
public string Target { get; set; }
|
||||
|
||||
[JsonProperty("via")]
|
||||
public string Via { get; set; }
|
||||
|
||||
[JsonProperty("flags")]
|
||||
public int Flags { get; set; }
|
||||
|
||||
[JsonProperty("metric")]
|
||||
public int Metric { get; set; }
|
||||
}
|
||||
}
|
||||
13
zerotierone/windows/WinUI/PreferencesView.xaml
Normal file
13
zerotierone/windows/WinUI/PreferencesView.xaml
Normal file
@@ -0,0 +1,13 @@
|
||||
<Window x:Class="WinUI.PreferencesView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:WinUI"
|
||||
mc:Ignorable="d"
|
||||
Title="PreferencesView" SizeToContent="WidthAndHeight" Height="Auto" Width="Auto" Icon="ZeroTierIcon.ico">
|
||||
<Grid>
|
||||
<CheckBox x:Name="startupCheckbox" Content="Launch ZeroTier On Startup" HorizontalAlignment="Left" Margin="10,10,10,10" VerticalAlignment="Top" Checked="startupCheckbox_Checked" Unchecked="startupCheckbox_Unchecked"/>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
||||
50
zerotierone/windows/WinUI/PreferencesView.xaml.cs
Normal file
50
zerotierone/windows/WinUI/PreferencesView.xaml.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace WinUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for PreferencesView.xaml
|
||||
/// </summary>
|
||||
public partial class PreferencesView : Window
|
||||
{
|
||||
public static string AppName = "ZeroTier One";
|
||||
private RegistryKey rk = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
|
||||
|
||||
public PreferencesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
|
||||
string keyValue = rk.GetValue(AppName) as string;
|
||||
|
||||
if (keyValue != null && keyValue.Equals(System.Reflection.Assembly.GetExecutingAssembly().Location))
|
||||
{
|
||||
startupCheckbox.IsChecked = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void startupCheckbox_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
rk.SetValue(AppName, System.Reflection.Assembly.GetExecutingAssembly().Location);
|
||||
}
|
||||
|
||||
private void startupCheckbox_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
rk.DeleteValue(AppName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
BIN
zerotierone/windows/WinUI/Resources/ZeroTierIcon.ico
Normal file
BIN
zerotierone/windows/WinUI/Resources/ZeroTierIcon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
59
zerotierone/windows/WinUI/ToolbarItem.xaml
Normal file
59
zerotierone/windows/WinUI/ToolbarItem.xaml
Normal file
@@ -0,0 +1,59 @@
|
||||
<Window x:Class="WinUI.ToolbarItem"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:WinUI"
|
||||
xmlns:tb="http://www.hardcodet.net/taskbar"
|
||||
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
|
||||
mc:Ignorable="d"
|
||||
Height="300" Width="300" Visibility="Hidden" Name="Toolbar">
|
||||
|
||||
<Window.Resources>
|
||||
<CollectionViewSource Source="{Binding ElementName=Toolbar, Path=NetworkCollection}" x:Key="KnownNetworks">
|
||||
<CollectionViewSource.SortDescriptions>
|
||||
<scm:SortDescription PropertyName="Header" Direction="Ascending"/>
|
||||
</CollectionViewSource.SortDescriptions>
|
||||
</CollectionViewSource>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<tb:TaskbarIcon x:Name="MyNotifyIcon"
|
||||
IconSource="ZeroTierIcon.ico"
|
||||
ToolTipText="ZeroTier One"
|
||||
MenuActivation="LeftOrRightClick">
|
||||
<tb:TaskbarIcon.ContextMenu>
|
||||
<ContextMenu>
|
||||
<ContextMenu.ItemsSource>
|
||||
<CompositeCollection>
|
||||
<MenuItem Header="Node ID: unknown"
|
||||
Click="ToolbarItem_NodeIDClicked"
|
||||
x:Name="nodeIdMenuItem"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Join Network..."
|
||||
Click="ToolbarItem_JoinNetworkClicked"/>
|
||||
<MenuItem Header="Show Networks..."
|
||||
Click="ToolbarItem_ShowNetworksClicked"/>
|
||||
<Separator/>
|
||||
|
||||
<CollectionContainer Collection="{Binding Source={StaticResource KnownNetworks}}">
|
||||
|
||||
</CollectionContainer>
|
||||
|
||||
<Separator/>
|
||||
<MenuItem Header="About..."
|
||||
Click="ToolbarItem_AboutClicked"/>
|
||||
<MenuItem Header="Preferences..."
|
||||
Click="ToolbarItem_PreferencesClicked"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Quit"
|
||||
Click="ToolbarItem_QuitClicked"/>
|
||||
|
||||
</CompositeCollection>
|
||||
</ContextMenu.ItemsSource>
|
||||
</ContextMenu>
|
||||
</tb:TaskbarIcon.ContextMenu>
|
||||
|
||||
</tb:TaskbarIcon>
|
||||
</Grid>
|
||||
</Window>
|
||||
310
zerotierone/windows/WinUI/ToolbarItem.xaml.cs
Normal file
310
zerotierone/windows/WinUI/ToolbarItem.xaml.cs
Normal file
@@ -0,0 +1,310 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Timers;
|
||||
using System.Windows.Threading;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace WinUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ToolbarItem.xaml
|
||||
/// </summary>
|
||||
public partial class ToolbarItem : Window, INotifyPropertyChanged
|
||||
{
|
||||
private APIHandler handler = APIHandler.Instance;
|
||||
|
||||
private Point netListLocation = new Point(0, 0);
|
||||
private Point joinNetLocation = new Point(0, 0);
|
||||
private Point aboutViewLocation = new Point(0, 0);
|
||||
private Point prefsViewLocation = new Point(0, 0);
|
||||
|
||||
private NetworkListView netListView = new NetworkListView();
|
||||
private JoinNetworkView joinNetView = null;
|
||||
private AboutView aboutView = null;
|
||||
private PreferencesView prefsView = null;
|
||||
|
||||
private NetworkMonitor mon = NetworkMonitor.Instance;
|
||||
|
||||
private ObservableCollection<MenuItem> _networkCollection = new ObservableCollection<MenuItem>();
|
||||
|
||||
public ObservableCollection<MenuItem> NetworkCollection
|
||||
{
|
||||
get { return _networkCollection; }
|
||||
set { _networkCollection = value; }
|
||||
}
|
||||
|
||||
private string nodeId;
|
||||
|
||||
public ToolbarItem()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
mon.SubscribeNetworkUpdates(updateNetworks);
|
||||
mon.SubscribeStatusUpdates(updateStatus);
|
||||
|
||||
SystemEvents.DisplaySettingsChanged += new EventHandler(SystemEvents_DisplaySettingsChanged);
|
||||
}
|
||||
|
||||
~ToolbarItem()
|
||||
{
|
||||
mon.UnsubscribeNetworkUpdates(updateNetworks);
|
||||
mon.UnsubscribeStatusUpdates(updateStatus);
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
private void updateNetworks(List<ZeroTierNetwork> networks)
|
||||
{
|
||||
if (networks != null)
|
||||
{
|
||||
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
|
||||
{
|
||||
NetworkCollection.Clear();
|
||||
foreach (ZeroTierNetwork n in networks)
|
||||
{
|
||||
MenuItem item = new MenuItem();
|
||||
item.Header = n.Title;
|
||||
item.DataContext = n;
|
||||
item.IsChecked = n.IsConnected;
|
||||
item.Click += ToolbarItem_NetworkClicked;
|
||||
|
||||
NetworkCollection.Add(item);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStatus(ZeroTierStatus status)
|
||||
{
|
||||
if (status != null)
|
||||
{
|
||||
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
|
||||
{
|
||||
nodeIdMenuItem.Header = "Node ID: " + status.Address;
|
||||
nodeIdMenuItem.IsEnabled = true;
|
||||
nodeId = status.Address;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private void ToolbarItem_NodeIDClicked(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
Clipboard.SetText(nodeId);
|
||||
}
|
||||
|
||||
private void ToolbarItem_ShowNetworksClicked(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
if (netListView == null)
|
||||
{
|
||||
netListView = new WinUI.NetworkListView();
|
||||
netListView.Closed += ShowNetworksClosed;
|
||||
}
|
||||
|
||||
bool netListNeedsMoving = true;
|
||||
if (netListLocation.X > 0 && netListLocation.Y > 0)
|
||||
{
|
||||
netListView.Left = netListLocation.X;
|
||||
netListView.Top = netListLocation.Y;
|
||||
netListNeedsMoving = false;
|
||||
}
|
||||
|
||||
netListView.Show();
|
||||
|
||||
if (netListNeedsMoving)
|
||||
{
|
||||
setWindowPosition(netListView);
|
||||
netListLocation.X = netListView.Left;
|
||||
netListLocation.Y = netListView.Top;
|
||||
}
|
||||
|
||||
netListView.Activate();
|
||||
}
|
||||
|
||||
private void ShowNetworksClosed(object sender, System.EventArgs e)
|
||||
{
|
||||
netListView = null;
|
||||
}
|
||||
|
||||
private void ToolbarItem_JoinNetworkClicked(object sender, System.EventArgs e)
|
||||
{
|
||||
if (joinNetView == null)
|
||||
{
|
||||
joinNetView = new JoinNetworkView();
|
||||
joinNetView.Closed += JoinNetworkClosed;
|
||||
|
||||
bool needsMove = true;
|
||||
if (joinNetLocation.X > 0 && joinNetLocation.Y > 0)
|
||||
{
|
||||
joinNetView.Left = joinNetLocation.X;
|
||||
joinNetView.Top = joinNetLocation.Y;
|
||||
needsMove = false;
|
||||
}
|
||||
|
||||
joinNetView.Show();
|
||||
|
||||
if (needsMove)
|
||||
{
|
||||
setWindowPosition(joinNetView);
|
||||
joinNetLocation.X = joinNetView.Left;
|
||||
joinNetLocation.Y = joinNetView.Top;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
joinNetView.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
private void JoinNetworkClosed(object sender, System.EventArgs e)
|
||||
{
|
||||
joinNetView = null;
|
||||
}
|
||||
|
||||
private void ToolbarItem_AboutClicked(object sender, System.EventArgs e)
|
||||
{
|
||||
if (aboutView == null)
|
||||
{
|
||||
aboutView = new AboutView();
|
||||
aboutView.Closed += AboutClosed;
|
||||
|
||||
bool needsMove = true;
|
||||
if (aboutViewLocation.X > 0 && aboutViewLocation.Y > 0)
|
||||
{
|
||||
aboutView.Left = aboutViewLocation.X;
|
||||
aboutView.Top = aboutViewLocation.Y;
|
||||
needsMove = false;
|
||||
}
|
||||
|
||||
aboutView.Show();
|
||||
|
||||
if (needsMove)
|
||||
{
|
||||
setWindowPosition(aboutView);
|
||||
aboutViewLocation.X = aboutView.Left;
|
||||
aboutViewLocation.Y = aboutView.Top;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aboutView.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
private void AboutClosed(object sender, System.EventArgs e)
|
||||
{
|
||||
aboutView = null;
|
||||
}
|
||||
|
||||
private void ToolbarItem_PreferencesClicked(object sender, System.EventArgs e)
|
||||
{
|
||||
if (prefsView == null)
|
||||
{
|
||||
prefsView = new PreferencesView();
|
||||
prefsView.Closed += PreferencesClosed;
|
||||
|
||||
bool needsMove = true;
|
||||
if (prefsViewLocation.X > 0 && prefsViewLocation.Y > 0)
|
||||
{
|
||||
prefsView.Left = prefsViewLocation.X;
|
||||
prefsView.Top = prefsViewLocation.Y;
|
||||
needsMove = false;
|
||||
}
|
||||
|
||||
prefsView.Show();
|
||||
|
||||
if (needsMove)
|
||||
{
|
||||
setWindowPosition(prefsView);
|
||||
prefsViewLocation.X = prefsView.Left;
|
||||
prefsViewLocation.Y = prefsView.Top;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prefsView.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
private void PreferencesClosed(object sender, System.EventArgs e)
|
||||
{
|
||||
prefsView = null;
|
||||
}
|
||||
|
||||
private void ToolbarItem_QuitClicked(object sender, System.EventArgs e)
|
||||
{
|
||||
NetworkMonitor.Instance.StopMonitor();
|
||||
this.Close();
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
|
||||
private void ToolbarItem_NetworkClicked(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
if(sender.GetType() == typeof(MenuItem))
|
||||
{
|
||||
MenuItem item = e.Source as MenuItem;
|
||||
if (item.DataContext != null)
|
||||
{
|
||||
ZeroTierNetwork network = item.DataContext as ZeroTierNetwork;
|
||||
if (item.IsChecked)
|
||||
{
|
||||
APIHandler.Instance.LeaveNetwork(network.NetworkId);
|
||||
}
|
||||
else
|
||||
{
|
||||
APIHandler.Instance.JoinNetwork(network.NetworkId, network.AllowManaged, network.AllowGlobal, network.AllowDefault);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setWindowPosition(Window w)
|
||||
{
|
||||
double width = w.ActualWidth;
|
||||
double height = w.ActualHeight;
|
||||
|
||||
double screenHeight = SystemParameters.PrimaryScreenHeight;
|
||||
double screenWidth = SystemParameters.PrimaryScreenWidth;
|
||||
|
||||
double top = screenHeight - height - 40;
|
||||
double left = screenWidth - width - 20;
|
||||
|
||||
w.Top = top;
|
||||
w.Left = left;
|
||||
}
|
||||
|
||||
private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
|
||||
{
|
||||
// reset cached locations to (0, 0) when display size changes
|
||||
netListLocation.X = 0;
|
||||
netListLocation.Y = 0;
|
||||
joinNetLocation.X = 0;
|
||||
joinNetLocation.Y = 0;
|
||||
aboutViewLocation.X = 0;
|
||||
aboutViewLocation.Y = 0;
|
||||
prefsViewLocation.X = 0;
|
||||
prefsViewLocation.Y = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
6
zerotierone/windows/copyutil/App.config
Normal file
6
zerotierone/windows/copyutil/App.config
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
</configuration>
|
||||
40
zerotierone/windows/copyutil/Program.cs
Normal file
40
zerotierone/windows/copyutil/Program.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace copyutil
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length != 2)
|
||||
{
|
||||
Console.WriteLine("Not enough arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(args[0]))
|
||||
{
|
||||
Console.WriteLine("Source directory doesn't exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Creating: " + args[1]);
|
||||
DirectoryInfo di = Directory.CreateDirectory(args[1]);
|
||||
|
||||
String authTokenSrc = args[0] + "\\authtoken.secret";
|
||||
String authTokenDest = args[1] + "\\authtoken.secret";
|
||||
|
||||
String portSrc = args[0] + "\\zerotier-one.port";
|
||||
String portDest = args[1] + "\\zerotier-one.port";
|
||||
|
||||
File.Copy(authTokenSrc, authTokenDest, true);
|
||||
File.Copy(portSrc, portDest, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
36
zerotierone/windows/copyutil/Properties/AssemblyInfo.cs
Normal file
36
zerotierone/windows/copyutil/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("copyutil")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("copyutil")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("6d27214a-087b-4484-b898-ad2a13fa3b9e")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
60
zerotierone/windows/copyutil/copyutil.csproj
Normal file
60
zerotierone/windows/copyutil/copyutil.csproj
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{6D27214A-087B-4484-B898-AD2A13FA3B9E}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>copyutil</RootNamespace>
|
||||
<AssemblyName>copyutil</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
162
zerotierone/zerotier-one.spec
Normal file
162
zerotierone/zerotier-one.spec
Normal file
@@ -0,0 +1,162 @@
|
||||
Name: zerotier-one
|
||||
Version: 1.1.14
|
||||
Release: 0.1%{?dist}
|
||||
Summary: ZeroTier One network virtualization service
|
||||
|
||||
License: GPLv3
|
||||
URL: https://www.zerotier.com
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
|
||||
%if 0%{?rhel} >= 7
|
||||
BuildRequires: systemd
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 21
|
||||
BuildRequires: libnatpmp-devel
|
||||
BuildRequires: systemd
|
||||
%endif
|
||||
|
||||
Requires: iproute
|
||||
|
||||
%if 0%{?rhel} >= 7
|
||||
Requires: systemd
|
||||
%endif
|
||||
|
||||
%if 0%{?rhel} <= 6
|
||||
Requires: chkconfig
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 21
|
||||
Requires: libnatpmp
|
||||
Requires: systemd
|
||||
%endif
|
||||
|
||||
Provides: bundled(http-parser) = 2.7.0
|
||||
Provides: bundled(miniupnpc) = 2.0.20161216
|
||||
|
||||
%if 0%{?rhel} >= 6
|
||||
Provides: bundled(libnatpmp) = 20131126
|
||||
%endif
|
||||
|
||||
%description
|
||||
ZeroTier is a software defined networking layer for Earth.
|
||||
|
||||
It can be used for on-premise network virtualization, as a peer to peer VPN
|
||||
for mobile teams, for hybrid or multi-data-center cloud deployments, or just
|
||||
about anywhere else secure software defined virtual networking is useful.
|
||||
|
||||
ZeroTier One is our OS-level client service. It allows Mac, Linux, Windows,
|
||||
FreeBSD, and soon other types of clients to join ZeroTier virtual networks
|
||||
like conventional VPNs or VLANs. It can run on native systems, VMs, or
|
||||
containers (Docker, OpenVZ, etc.).
|
||||
|
||||
%prep
|
||||
rm -rf *
|
||||
ln -s %{getenv:PWD} %{name}-%{version}
|
||||
tar --exclude=%{name}-%{version}/.git --exclude=%{name}-%{version}/%{name}-%{version} -czf %{_sourcedir}/%{name}-%{version}.tar.gz %{name}-%{version}/*
|
||||
rm -f %{name}-%{version}
|
||||
cp -a %{getenv:PWD}/* .
|
||||
|
||||
%build
|
||||
%if 0%{?rhel} <= 7
|
||||
make CFLAGS="`echo %{optflags} | sed s/stack-protector-strong/stack-protector/`" CXXFLAGS="`echo %{optflags} | sed s/stack-protector-strong/stack-protector/`" ZT_USE_MINIUPNPC=1 %{?_smp_mflags} one manpages selftest
|
||||
%else
|
||||
make CFLAGS="%{optflags}" CXXFLAGS="%{optflags}" ZT_USE_MINIUPNPC=1 %{?_smp_mflags} one manpages selftest
|
||||
%endif
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
make install DESTDIR=$RPM_BUILD_ROOT
|
||||
%if 0%{?rhel} >= 7
|
||||
mkdir -p $RPM_BUILD_ROOT%{_unitdir}
|
||||
cp debian/zerotier-one.service $RPM_BUILD_ROOT%{_unitdir}/%{name}.service
|
||||
%endif
|
||||
%if 0%{?fedora} >= 21
|
||||
mkdir -p $RPM_BUILD_ROOT%{_unitdir}
|
||||
cp debian/zerotier-one.service $RPM_BUILD_ROOT%{_unitdir}/%{name}.service
|
||||
%endif
|
||||
%if 0%{?rhel} <= 6
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/init.d
|
||||
cp ext/installfiles/linux/zerotier-one.init.rhel6 $RPM_BUILD_ROOT/etc/init.d/zerotier-one
|
||||
chmod 0755 $RPM_BUILD_ROOT/etc/init.d/zerotier-one
|
||||
%endif
|
||||
|
||||
%files
|
||||
%{_sbindir}/*
|
||||
%{_mandir}/*
|
||||
%{_localstatedir}/*
|
||||
%if 0%{?rhel} >= 7
|
||||
%{_unitdir}/%{name}.service
|
||||
%endif
|
||||
%if 0%{?fedora} >= 21
|
||||
%{_unitdir}/%{name}.service
|
||||
%endif
|
||||
%if 0%{?rhel} <= 6
|
||||
/etc/init.d/zerotier-one
|
||||
%endif
|
||||
|
||||
%post
|
||||
%if 0%{?rhel} >= 7
|
||||
%systemd_post zerotier-one.service
|
||||
%endif
|
||||
%if 0%{?fedora} >= 21
|
||||
%systemd_post zerotier-one.service
|
||||
%endif
|
||||
%if 0%{?rhel} <= 6
|
||||
case "$1" in
|
||||
1)
|
||||
chkconfig --add zerotier-one
|
||||
;;
|
||||
2)
|
||||
chkconfig --del newservice
|
||||
chkconfig --add newservice
|
||||
;;
|
||||
esac
|
||||
%endif
|
||||
|
||||
%preun
|
||||
%if 0%{?rhel} >= 7
|
||||
%systemd_preun zerotier-one.service
|
||||
%endif
|
||||
%if 0%{?fedora} >= 21
|
||||
%systemd_preun zerotier-one.service
|
||||
%endif
|
||||
%if 0%{?rhel} <= 6
|
||||
case "$1" in
|
||||
0)
|
||||
service zerotier-one stop
|
||||
chkconfig --del zerotier-one
|
||||
;;
|
||||
1)
|
||||
# This is an upgrade.
|
||||
:
|
||||
;;
|
||||
esac
|
||||
%endif
|
||||
|
||||
%postun
|
||||
%if 0%{?rhel} >= 7
|
||||
%systemd_postun_with_restart zerotier-one.service
|
||||
%endif
|
||||
%if 0%{?fedora} >= 21
|
||||
%systemd_postun_with_restart zerotier-one.service
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Tue Jul 12 2016 Adam Ierymenko <adam.ierymenko@zerotier.com> - 1.1.10-0.1
|
||||
- see https://github.com/zerotier/ZeroTierOne for release notes
|
||||
|
||||
* Fri Jul 08 2016 Adam Ierymenko <adam.ierymenko@zerotier.com> - 1.1.8-0.1
|
||||
- see https://github.com/zerotier/ZeroTierOne for release notes
|
||||
|
||||
* Sat Jun 25 2016 Adam Ierymenko <adam.ierymenko@zerotier.com> - 1.1.6-0.1
|
||||
- now builds on CentOS 6 as well as newer distros, and some cleanup
|
||||
|
||||
* Wed Jun 08 2016 François Kooman <fkooman@tuxed.net> - 1.1.5-0.3
|
||||
- include systemd unit file
|
||||
|
||||
* Wed Jun 08 2016 François Kooman <fkooman@tuxed.net> - 1.1.5-0.2
|
||||
- add libnatpmp as (build)dependency
|
||||
|
||||
* Wed Jun 08 2016 François Kooman <fkooman@tuxed.net> - 1.1.5-0.1
|
||||
- initial package
|
||||
Reference in New Issue
Block a user