mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-03 19:13:43 +02:00
Merge 6fa849c956
into f4053c8af3
This commit is contained in:
commit
d375884a5c
27 changed files with 3411 additions and 2059 deletions
1851
controller/CV1.cpp
Normal file
1851
controller/CV1.cpp
Normal file
File diff suppressed because it is too large
Load diff
144
controller/CV1.hpp
Normal file
144
controller/CV1.hpp
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c)2019 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2026-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#include "DB.hpp"
|
||||
|
||||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||
|
||||
#ifndef ZT_CONTROLLER_CV1_HPP
|
||||
#define ZT_CONTROLLER_CV1_HPP
|
||||
|
||||
#define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4
|
||||
|
||||
#include "ConnectionPool.hpp"
|
||||
#include <pqxx/pqxx>
|
||||
|
||||
#include <memory>
|
||||
#include <redis++/redis++.h>
|
||||
|
||||
#include "../node/Metrics.hpp"
|
||||
|
||||
#include "PostgreSQL.hpp"
|
||||
|
||||
|
||||
namespace smeeclient {
|
||||
struct SmeeClient;
|
||||
}
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
struct RedisConfig;
|
||||
|
||||
/**
|
||||
* A controller database driver that talks to PostgreSQL
|
||||
*
|
||||
* This is for use with ZeroTier Central. Others are free to build and use it
|
||||
* but be aware that we might change it at any time.
|
||||
*/
|
||||
class CV1 : public DB
|
||||
{
|
||||
public:
|
||||
CV1(const Identity &myId, const char *path, int listenPort, RedisConfig *rc);
|
||||
virtual ~CV1();
|
||||
|
||||
virtual bool waitForReady();
|
||||
virtual bool isReady();
|
||||
virtual bool save(nlohmann::json &record,bool notifyListeners);
|
||||
virtual void eraseNetwork(const uint64_t networkId);
|
||||
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
|
||||
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress);
|
||||
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch);
|
||||
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL);
|
||||
|
||||
virtual bool ready() {
|
||||
return _ready == 2;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct _PairHasher
|
||||
{
|
||||
inline std::size_t operator()(const std::pair<uint64_t,uint64_t> &p) const { return (std::size_t)(p.first ^ p.second); }
|
||||
};
|
||||
virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners) {
|
||||
DB::_memberChanged(old, memberConfig, notifyListeners);
|
||||
}
|
||||
|
||||
virtual void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners) {
|
||||
DB::_networkChanged(old, networkConfig, notifyListeners);
|
||||
}
|
||||
|
||||
private:
|
||||
void initializeNetworks();
|
||||
void initializeMembers();
|
||||
void heartbeat();
|
||||
void membersDbWatcher();
|
||||
void _membersWatcher_Postgres();
|
||||
void networksDbWatcher();
|
||||
void _networksWatcher_Postgres();
|
||||
|
||||
void _membersWatcher_Redis();
|
||||
void _networksWatcher_Redis();
|
||||
|
||||
void commitThread();
|
||||
void onlineNotificationThread();
|
||||
void onlineNotification_Postgres();
|
||||
void onlineNotification_Redis();
|
||||
uint64_t _doRedisUpdate(sw::redis::Transaction &tx, std::string &controllerId,
|
||||
std::unordered_map< std::pair<uint64_t,uint64_t>,NodeOnlineRecord,_PairHasher > &lastOnline);
|
||||
|
||||
void configureSmee();
|
||||
void notifyNewMember(const std::string &networkID, const std::string &memberID);
|
||||
|
||||
enum OverrideMode {
|
||||
ALLOW_PGBOUNCER_OVERRIDE = 0,
|
||||
NO_OVERRIDE = 1
|
||||
};
|
||||
|
||||
std::shared_ptr<ConnectionPool<PostgresConnection> > _pool;
|
||||
|
||||
const Identity _myId;
|
||||
const Address _myAddress;
|
||||
std::string _myAddressStr;
|
||||
std::string _connString;
|
||||
|
||||
BlockingQueue< std::pair<nlohmann::json,bool> > _commitQueue;
|
||||
|
||||
std::thread _heartbeatThread;
|
||||
std::thread _membersDbWatcher;
|
||||
std::thread _networksDbWatcher;
|
||||
std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS];
|
||||
std::thread _onlineNotificationThread;
|
||||
|
||||
std::unordered_map< std::pair<uint64_t,uint64_t>,NodeOnlineRecord,_PairHasher > _lastOnline;
|
||||
|
||||
mutable std::mutex _lastOnline_l;
|
||||
mutable std::mutex _readyLock;
|
||||
std::atomic<int> _ready, _connected, _run;
|
||||
mutable volatile bool _waitNoticePrinted;
|
||||
|
||||
int _listenPort;
|
||||
uint8_t _ssoPsk[48];
|
||||
|
||||
RedisConfig *_rc;
|
||||
std::shared_ptr<sw::redis::Redis> _redis;
|
||||
std::shared_ptr<sw::redis::RedisCluster> _cluster;
|
||||
bool _redisMemberStatus;
|
||||
|
||||
smeeclient::SmeeClient *_smee;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif // ZT_CONTROLLER_CV1_HPP
|
||||
|
||||
#endif // ZT_CONTROLLER_USE_LIBPQ
|
1046
controller/CV2.cpp
Normal file
1046
controller/CV2.cpp
Normal file
File diff suppressed because it is too large
Load diff
113
controller/CV2.hpp
Normal file
113
controller/CV2.hpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c)2025 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2026-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#include "DB.hpp"
|
||||
|
||||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||
|
||||
#ifndef ZT_CONTROLLER_CV2_HPP
|
||||
#define ZT_CONTROLLER_CV2_HPP
|
||||
|
||||
#define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4
|
||||
|
||||
#include "ConnectionPool.hpp"
|
||||
#include <pqxx/pqxx>
|
||||
|
||||
#include <memory>
|
||||
#include <redis++/redis++.h>
|
||||
|
||||
#include "../node/Metrics.hpp"
|
||||
|
||||
#include "PostgreSQL.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class CV2 : public DB
|
||||
{
|
||||
public:
|
||||
CV2(const Identity &myId, const char *path, int listenPort);
|
||||
virtual ~CV2();
|
||||
|
||||
virtual bool waitForReady();
|
||||
virtual bool isReady();
|
||||
virtual bool save(nlohmann::json &record,bool notifyListeners);
|
||||
virtual void eraseNetwork(const uint64_t networkId);
|
||||
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
|
||||
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress);
|
||||
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch);
|
||||
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL);
|
||||
|
||||
virtual bool ready() {
|
||||
return _ready == 2;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct _PairHasher
|
||||
{
|
||||
inline std::size_t operator()(const std::pair<uint64_t,uint64_t> &p) const { return (std::size_t)(p.first ^ p.second); }
|
||||
};
|
||||
virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners) {
|
||||
DB::_memberChanged(old, memberConfig, notifyListeners);
|
||||
}
|
||||
|
||||
virtual void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners) {
|
||||
DB::_networkChanged(old, networkConfig, notifyListeners);
|
||||
}
|
||||
|
||||
private:
|
||||
void initializeNetworks();
|
||||
void initializeMembers();
|
||||
void heartbeat();
|
||||
void membersDbWatcher();
|
||||
void networksDbWatcher();
|
||||
|
||||
void commitThread();
|
||||
void onlineNotificationThread();
|
||||
|
||||
// void notifyNewMember(const std::string &networkID, const std::string &memberID);
|
||||
|
||||
enum OverrideMode {
|
||||
ALLOW_PGBOUNCER_OVERRIDE = 0,
|
||||
NO_OVERRIDE = 1
|
||||
};
|
||||
|
||||
std::shared_ptr<ConnectionPool<PostgresConnection> > _pool;
|
||||
|
||||
const Identity _myId;
|
||||
const Address _myAddress;
|
||||
std::string _myAddressStr;
|
||||
std::string _connString;
|
||||
|
||||
BlockingQueue< std::pair<nlohmann::json,bool> > _commitQueue;
|
||||
|
||||
std::thread _heartbeatThread;
|
||||
std::thread _membersDbWatcher;
|
||||
std::thread _networksDbWatcher;
|
||||
std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS];
|
||||
std::thread _onlineNotificationThread;
|
||||
|
||||
std::unordered_map< std::pair<uint64_t,uint64_t>,NodeOnlineRecord,_PairHasher > _lastOnline;
|
||||
|
||||
mutable std::mutex _lastOnline_l;
|
||||
mutable std::mutex _readyLock;
|
||||
std::atomic<int> _ready, _connected, _run;
|
||||
mutable volatile bool _waitNoticePrinted;
|
||||
|
||||
int _listenPort;
|
||||
uint8_t _ssoPsk[48];
|
||||
};
|
||||
|
||||
} // namespace Zerotier
|
||||
|
||||
#endif // ZT_CONTROLLER_CV2_HPP
|
||||
#endif // ZT_CONTROLLER_USE_LIBPQ
|
62
controller/CtlUtil.cpp
Normal file
62
controller/CtlUtil.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include "CtlUtil.hpp"
|
||||
|
||||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
const char *_timestr()
|
||||
{
|
||||
time_t t = time(0);
|
||||
char *ts = ctime(&t);
|
||||
char *p = ts;
|
||||
if (!p)
|
||||
return "";
|
||||
while (*p) {
|
||||
if (*p == '\n') {
|
||||
*p = (char)0;
|
||||
break;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string str, char delim){
|
||||
std::istringstream iss(str);
|
||||
std::vector<std::string> tokens;
|
||||
std::string item;
|
||||
while(std::getline(iss, item, delim)) {
|
||||
tokens.push_back(item);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
std::string url_encode(const std::string &value) {
|
||||
std::ostringstream escaped;
|
||||
escaped.fill('0');
|
||||
escaped << std::hex;
|
||||
|
||||
for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
|
||||
std::string::value_type c = (*i);
|
||||
|
||||
// Keep alphanumeric and other accepted characters intact
|
||||
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
|
||||
escaped << c;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Any other characters are percent-encoded
|
||||
escaped << std::uppercase;
|
||||
escaped << '%' << std::setw(2) << int((unsigned char) c);
|
||||
escaped << std::nouppercase;
|
||||
}
|
||||
|
||||
return escaped.str();
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
16
controller/CtlUtil.hpp
Normal file
16
controller/CtlUtil.hpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef ZT_CTLUTIL_HPP
|
||||
#define ZT_CTLUTIL_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
const char *_timestr();
|
||||
|
||||
std::vector<std::string> split(std::string str, char delim);
|
||||
|
||||
std::string url_encode(const std::string &value);
|
||||
}
|
||||
|
||||
#endif // namespace ZeroTier
|
|
@ -75,6 +75,10 @@ public:
|
|||
*/
|
||||
class DB
|
||||
{
|
||||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||
friend class MemberNotificationReceiver;
|
||||
friend class NetworkNotificationReceiver;
|
||||
#endif
|
||||
public:
|
||||
class ChangeListener
|
||||
{
|
||||
|
@ -137,6 +141,7 @@ public:
|
|||
virtual void eraseNetwork(const uint64_t networkId) = 0;
|
||||
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId) = 0;
|
||||
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) = 0;
|
||||
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch) = 0;
|
||||
|
||||
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) { return AuthInfo(); }
|
||||
|
||||
|
|
|
@ -206,14 +206,18 @@ void DBMirrorSet::eraseMember(const uint64_t networkId,const uint64_t memberId)
|
|||
}
|
||||
}
|
||||
|
||||
void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
|
||||
{
|
||||
void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch) {
|
||||
std::shared_lock<std::shared_mutex> l(_dbs_l);
|
||||
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
|
||||
(*d)->nodeIsOnline(networkId,memberId,physicalAddress);
|
||||
}
|
||||
}
|
||||
|
||||
void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
|
||||
{
|
||||
this->nodeIsOnline(networkId,memberId,physicalAddress,"unknown/unknown");
|
||||
}
|
||||
|
||||
void DBMirrorSet::onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network)
|
||||
{
|
||||
nlohmann::json record(network);
|
||||
|
|
|
@ -44,7 +44,8 @@ public:
|
|||
bool save(nlohmann::json &record,bool notifyListeners);
|
||||
void eraseNetwork(const uint64_t networkId);
|
||||
void eraseMember(const uint64_t networkId,const uint64_t memberId);
|
||||
void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
|
||||
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
|
||||
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch);
|
||||
|
||||
// These are called by various DB instances when changes occur.
|
||||
virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network);
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
#include "LFDB.hpp"
|
||||
#include "FileDB.hpp"
|
||||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||
#include "PostgreSQL.hpp"
|
||||
#include "CV1.hpp"
|
||||
#include "CV2.hpp"
|
||||
#endif
|
||||
|
||||
#include "../node/Node.hpp"
|
||||
|
@ -534,8 +535,13 @@ void EmbeddedNetworkController::init(const Identity &signingId,Sender *sender)
|
|||
|
||||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||
if ((_path.length() > 9)&&(_path.substr(0,9) == "postgres:")) {
|
||||
_db.addDB(std::shared_ptr<DB>(new PostgreSQL(_signingId,_path.substr(9).c_str(), _listenPort, _rc)));
|
||||
fprintf(stderr, "CV1\n");
|
||||
_db.addDB(std::shared_ptr<DB>(new CV1(_signingId,_path.substr(9).c_str(), _listenPort, _rc)));
|
||||
} else if ((_path.length() > 4)&&(_path.substr(0,4) == "cv2:")) {
|
||||
fprintf(stderr, "CV2\n");
|
||||
_db.addDB(std::shared_ptr<DB>(new CV2(_signingId,_path.substr(4).c_str(),_listenPort)));
|
||||
} else {
|
||||
fprintf(stderr, "FileDB\n");
|
||||
#endif
|
||||
_db.addDB(std::shared_ptr<DB>(new FileDB(_path.c_str())));
|
||||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||
|
|
|
@ -155,8 +155,7 @@ void FileDB::eraseMember(const uint64_t networkId,const uint64_t memberId)
|
|||
this->_online[networkId].erase(memberId);
|
||||
}
|
||||
|
||||
void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
|
||||
{
|
||||
void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch) {
|
||||
char mid[32],atmp[64];
|
||||
OSUtils::ztsnprintf(mid,sizeof(mid),"%.10llx",(unsigned long long)memberId);
|
||||
physicalAddress.toString(atmp);
|
||||
|
@ -164,4 +163,9 @@ void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const
|
|||
this->_online[networkId][memberId][OSUtils::now()] = physicalAddress;
|
||||
}
|
||||
|
||||
void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
|
||||
{
|
||||
this->nodeIsOnline(networkId,memberId,physicalAddress,"unknown/unknown");
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -31,7 +31,8 @@ public:
|
|||
virtual void eraseNetwork(const uint64_t networkId);
|
||||
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId);
|
||||
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
|
||||
|
||||
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch);
|
||||
|
||||
protected:
|
||||
std::string _path;
|
||||
std::string _networksPath;
|
||||
|
|
|
@ -388,7 +388,7 @@ void LFDB::eraseMember(const uint64_t networkId,const uint64_t memberId)
|
|||
// TODO
|
||||
}
|
||||
|
||||
void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
|
||||
void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress,const char *osArch)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_state_l);
|
||||
auto nw = _state.find(networkId);
|
||||
|
@ -403,4 +403,9 @@ void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const I
|
|||
}
|
||||
}
|
||||
|
||||
void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
|
||||
{
|
||||
this->nodeIsOnline(networkId,memberId,physicalAddress,"unknown/unknown");
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -47,7 +47,8 @@ public:
|
|||
virtual void eraseNetwork(const uint64_t networkId);
|
||||
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId);
|
||||
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
|
||||
|
||||
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress, const char *osArch);
|
||||
|
||||
protected:
|
||||
const Identity _myId;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c)2019 ZeroTier, Inc.
|
||||
* Copyright (c)2025 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
|
@ -11,35 +11,22 @@
|
|||
*/
|
||||
/****/
|
||||
|
||||
#include "DB.hpp"
|
||||
|
||||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||
|
||||
#ifndef ZT_CONTROLLER_LIBPQ_HPP
|
||||
#define ZT_CONTROLLER_LIBPQ_HPP
|
||||
|
||||
#define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4
|
||||
#ifndef ZT_CONTROLLER_POSTGRESQL_HPP
|
||||
#define ZT_CONTROLLER_POSTGRESQL_HPP
|
||||
|
||||
#include "DB.hpp"
|
||||
#include "ConnectionPool.hpp"
|
||||
#include <pqxx/pqxx>
|
||||
|
||||
#include <memory>
|
||||
#include <redis++/redis++.h>
|
||||
|
||||
#include "../node/Metrics.hpp"
|
||||
namespace ZeroTier {
|
||||
|
||||
extern "C" {
|
||||
typedef struct pg_conn PGconn;
|
||||
}
|
||||
|
||||
namespace smeeclient {
|
||||
struct SmeeClient;
|
||||
}
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
struct RedisConfig;
|
||||
|
||||
|
||||
class PostgresConnection : public Connection {
|
||||
public:
|
||||
|
@ -68,129 +55,38 @@ private:
|
|||
std::string m_connString;
|
||||
};
|
||||
|
||||
class PostgreSQL;
|
||||
|
||||
class MemberNotificationReceiver : public pqxx::notification_receiver {
|
||||
public:
|
||||
MemberNotificationReceiver(PostgreSQL *p, pqxx::connection &c, const std::string &channel);
|
||||
MemberNotificationReceiver(DB *p, pqxx::connection &c, const std::string &channel);
|
||||
virtual ~MemberNotificationReceiver() {
|
||||
fprintf(stderr, "MemberNotificationReceiver destroyed\n");
|
||||
}
|
||||
|
||||
virtual void operator() (const std::string &payload, int backendPid);
|
||||
private:
|
||||
PostgreSQL *_psql;
|
||||
DB *_psql;
|
||||
};
|
||||
|
||||
class NetworkNotificationReceiver : public pqxx::notification_receiver {
|
||||
public:
|
||||
NetworkNotificationReceiver(PostgreSQL *p, pqxx::connection &c, const std::string &channel);
|
||||
NetworkNotificationReceiver(DB *p, pqxx::connection &c, const std::string &channel);
|
||||
virtual ~NetworkNotificationReceiver() {
|
||||
fprintf(stderr, "NetworkNotificationReceiver destroyed\n");
|
||||
};
|
||||
|
||||
virtual void operator() (const std::string &payload, int packend_pid);
|
||||
private:
|
||||
PostgreSQL *_psql;
|
||||
DB *_psql;
|
||||
};
|
||||
|
||||
/**
|
||||
* A controller database driver that talks to PostgreSQL
|
||||
*
|
||||
* This is for use with ZeroTier Central. Others are free to build and use it
|
||||
* but be aware that we might change it at any time.
|
||||
*/
|
||||
class PostgreSQL : public DB
|
||||
{
|
||||
friend class MemberNotificationReceiver;
|
||||
friend class NetworkNotificationReceiver;
|
||||
public:
|
||||
PostgreSQL(const Identity &myId, const char *path, int listenPort, RedisConfig *rc);
|
||||
virtual ~PostgreSQL();
|
||||
|
||||
virtual bool waitForReady();
|
||||
virtual bool isReady();
|
||||
virtual bool save(nlohmann::json &record,bool notifyListeners);
|
||||
virtual void eraseNetwork(const uint64_t networkId);
|
||||
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
|
||||
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress);
|
||||
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL);
|
||||
|
||||
protected:
|
||||
struct _PairHasher
|
||||
{
|
||||
inline std::size_t operator()(const std::pair<uint64_t,uint64_t> &p) const { return (std::size_t)(p.first ^ p.second); }
|
||||
};
|
||||
virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners) {
|
||||
DB::_memberChanged(old, memberConfig, notifyListeners);
|
||||
}
|
||||
|
||||
virtual void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners) {
|
||||
DB::_networkChanged(old, networkConfig, notifyListeners);
|
||||
}
|
||||
|
||||
private:
|
||||
void initializeNetworks();
|
||||
void initializeMembers();
|
||||
void heartbeat();
|
||||
void membersDbWatcher();
|
||||
void _membersWatcher_Postgres();
|
||||
void networksDbWatcher();
|
||||
void _networksWatcher_Postgres();
|
||||
|
||||
void _membersWatcher_Redis();
|
||||
void _networksWatcher_Redis();
|
||||
|
||||
void commitThread();
|
||||
void onlineNotificationThread();
|
||||
void onlineNotification_Postgres();
|
||||
void onlineNotification_Redis();
|
||||
uint64_t _doRedisUpdate(sw::redis::Transaction &tx, std::string &controllerId,
|
||||
std::unordered_map< std::pair<uint64_t,uint64_t>,std::pair<int64_t,InetAddress>,_PairHasher > &lastOnline);
|
||||
|
||||
void configureSmee();
|
||||
void notifyNewMember(const std::string &networkID, const std::string &memberID);
|
||||
|
||||
enum OverrideMode {
|
||||
ALLOW_PGBOUNCER_OVERRIDE = 0,
|
||||
NO_OVERRIDE = 1
|
||||
};
|
||||
|
||||
std::shared_ptr<ConnectionPool<PostgresConnection> > _pool;
|
||||
|
||||
const Identity _myId;
|
||||
const Address _myAddress;
|
||||
std::string _myAddressStr;
|
||||
std::string _connString;
|
||||
|
||||
BlockingQueue< std::pair<nlohmann::json,bool> > _commitQueue;
|
||||
|
||||
std::thread _heartbeatThread;
|
||||
std::thread _membersDbWatcher;
|
||||
std::thread _networksDbWatcher;
|
||||
std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS];
|
||||
std::thread _onlineNotificationThread;
|
||||
|
||||
std::unordered_map< std::pair<uint64_t,uint64_t>,std::pair<int64_t,InetAddress>,_PairHasher > _lastOnline;
|
||||
|
||||
mutable std::mutex _lastOnline_l;
|
||||
mutable std::mutex _readyLock;
|
||||
std::atomic<int> _ready, _connected, _run;
|
||||
mutable volatile bool _waitNoticePrinted;
|
||||
|
||||
int _listenPort;
|
||||
uint8_t _ssoPsk[48];
|
||||
|
||||
RedisConfig *_rc;
|
||||
std::shared_ptr<sw::redis::Redis> _redis;
|
||||
std::shared_ptr<sw::redis::RedisCluster> _cluster;
|
||||
bool _redisMemberStatus;
|
||||
|
||||
smeeclient::SmeeClient *_smee;
|
||||
struct NodeOnlineRecord {
|
||||
uint64_t lastSeen;
|
||||
InetAddress physicalAddress;
|
||||
std::string osArch;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif // ZT_CONTROLLER_LIBPQ_HPP
|
||||
#endif // ZT_CONTROLLER_POSTGRESQL_HPP
|
||||
|
||||
#endif // ZT_CONTROLLER_USE_LIBPQ
|
||||
#endif // ZT_CONTROLLER_USE_LIBPQ
|
|
@ -1,11 +1,16 @@
|
|||
# Dockerfile for ZeroTier Central Controllers
|
||||
FROM registry.zerotier.com/zerotier/ctlbuild:latest as builder
|
||||
MAINTAINER Adam Ierymekno <adam.ierymenko@zerotier.com>, Grant Limberg <grant.limberg@zerotier.com>
|
||||
FROM registry.zerotier.com/zerotier/ctlbuild:2025-05-13-01 AS builder
|
||||
ADD . /ZeroTierOne
|
||||
RUN export PATH=$PATH:~/.cargo/bin && cd ZeroTierOne && make clean && make central-controller -j8
|
||||
|
||||
FROM registry.zerotier.com/zerotier/ctlrun:latest
|
||||
FROM golang:bookworm AS go_base
|
||||
RUN go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
|
||||
|
||||
FROM registry.zerotier.com/zerotier/ctlrun:2025-05-13-01
|
||||
COPY --from=builder /ZeroTierOne/zerotier-one /usr/local/bin/zerotier-one
|
||||
COPY --from=go_base /go/bin/migrate /usr/local/bin/migrate
|
||||
COPY ext/central-controller-docker/migrations /migrations
|
||||
|
||||
RUN chmod a+x /usr/local/bin/zerotier-one
|
||||
RUN echo "/usr/local/lib64" > /etc/ld.so.conf.d/usr-local-lib64.conf && ldconfig
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
# Dockerfile for building ZeroTier Central Controllers
|
||||
FROM ubuntu:jammy as builder
|
||||
MAINTAINER Adam Ierymekno <adam.ierymenko@zerotier.com>, Grant Limberg <grant.limberg@zerotier.com>
|
||||
|
||||
ARG git_branch=master
|
||||
FROM debian:bookworm
|
||||
|
||||
RUN apt update && apt upgrade -y
|
||||
RUN apt -y install \
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
FROM ubuntu:jammy
|
||||
FROM debian:bookworm
|
||||
|
||||
|
||||
|
||||
RUN apt update && apt upgrade -y
|
||||
|
||||
RUN apt -y install \
|
||||
netcat \
|
||||
netcat-traditional \
|
||||
postgresql-client \
|
||||
postgresql-client-common \
|
||||
libjemalloc2 \
|
||||
libpq5 \
|
||||
curl \
|
||||
binutils \
|
||||
linux-tools-gke \
|
||||
perf-tools-unstable \
|
||||
google-perftools
|
||||
google-perftools \
|
||||
gnupg
|
||||
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ -z "$ZT_IDENTITY_PATH" ]; then
|
||||
echo '*** FAILED: ZT_IDENTITY_PATH environment variable is not defined'
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$ZT_DB_HOST" ]; then
|
||||
echo '*** FAILED: ZT_DB_HOST environment variable not defined'
|
||||
exit 1
|
||||
|
@ -24,6 +20,9 @@ if [ -z "$ZT_DB_PASSWORD" ]; then
|
|||
echo '*** FAILED: ZT_DB_PASSWORD environment variable not defined'
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$ZT_DB_TYPE" ]; then
|
||||
ZT_DB_TYPE="postgres"
|
||||
fi
|
||||
|
||||
REDIS=""
|
||||
if [ "$ZT_USE_REDIS" == "true" ]; then
|
||||
|
@ -56,10 +55,14 @@ fi
|
|||
mkdir -p /var/lib/zerotier-one
|
||||
|
||||
pushd /var/lib/zerotier-one
|
||||
ln -s $ZT_IDENTITY_PATH/identity.public identity.public
|
||||
ln -s $ZT_IDENTITY_PATH/identity.secret identity.secret
|
||||
if [ -f "$ZT_IDENTITY_PATH/authtoken.secret" ]; then
|
||||
ln -s $ZT_IDENTITY_PATH/authtoken.secret authtoken.secret
|
||||
if [ -d "$ZT_IDENTITY_PATH" ]; then
|
||||
echo '*** Using existing ZT identity from path $ZT_IDENTITY_PATH'
|
||||
|
||||
ln -s $ZT_IDENTITY_PATH/identity.public identity.public
|
||||
ln -s $ZT_IDENTITY_PATH/identity.secret identity.secret
|
||||
if [ -f "$ZT_IDENTITY_PATH/authtoken.secret" ]; then
|
||||
ln -s $ZT_IDENTITY_PATH/authtoken.secret authtoken.secret
|
||||
fi
|
||||
fi
|
||||
popd
|
||||
|
||||
|
@ -70,7 +73,7 @@ APP_NAME="controller-$(cat /var/lib/zerotier-one/identity.public | cut -d ':' -f
|
|||
|
||||
echo "{
|
||||
\"settings\": {
|
||||
\"controllerDbPath\": \"postgres:host=${ZT_DB_HOST} port=${ZT_DB_PORT} dbname=${ZT_DB_NAME} user=${ZT_DB_USER} password=${ZT_DB_PASSWORD} application_name=${APP_NAME} sslmode=prefer sslcert=${DB_CLIENT_CERT} sslkey=${DB_CLIENT_KEY} sslrootcert=${DB_SERVER_CA}\",
|
||||
\"controllerDbPath\": \"${ZT_DB_TYPE}:host=${ZT_DB_HOST} port=${ZT_DB_PORT} dbname=${ZT_DB_NAME} user=${ZT_DB_USER} password=${ZT_DB_PASSWORD} application_name=${APP_NAME} sslmode=prefer sslcert=${DB_CLIENT_CERT} sslkey=${DB_CLIENT_KEY} sslrootcert=${DB_SERVER_CA}\",
|
||||
\"portMappingEnabled\": true,
|
||||
\"softwareUpdate\": \"disable\",
|
||||
\"interfacePrefixBlacklist\": [
|
||||
|
@ -100,6 +103,15 @@ else
|
|||
done
|
||||
fi
|
||||
|
||||
if [ "$ZT_DB_TYPE" == "cv2" ]; then
|
||||
echo "Migrating database (if needed)..."
|
||||
if [ -n "$DB_SERVER_CA" ]; then
|
||||
/usr/local/bin/migrate -source file:///migrations -database "postgres://$ZT_DB_USER:$ZT_DB_PASSWORD@$ZT_DB_HOST:$ZT_DB_PORT/$ZT_DB_NAME?x-migrations-table=controller_migrations&sslmode=verify-full&sslrootcert=$DB_SERVER_CA&sslcert=$DB_CLIENT_CERT&sslkey=$DB_CLIENT_KEY" up
|
||||
else
|
||||
/usr/local/bin/migrate -source file:///migrations -database "postgres://$ZT_DB_USER:$ZT_DB_PASSWORD@$ZT_DB_HOST:$ZT_DB_PORT/$ZT_DB_NAME?x-migrations-table=controller_migrations&sslmode=disable" up
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$ZT_TEMPORAL_HOST" ] && [ -n "$ZT_TEMPORAL_PORT" ]; then
|
||||
echo "waiting for temporal..."
|
||||
while ! nc -z ${ZT_TEMPORAL_HOST} ${ZT_TEMPORAL_PORT}; do
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
DROP TABLE IF EXISTS network_memberships_ctl;
|
||||
DROP TABLE IF EXISTS networks_ctl;
|
||||
DROP TABLE IF EXISTS controllers_ctl;
|
47
ext/central-controller-docker/migrations/0001_init.up.sql
Normal file
47
ext/central-controller-docker/migrations/0001_init.up.sql
Normal file
|
@ -0,0 +1,47 @@
|
|||
-- inits controller db schema
|
||||
|
||||
CREATE TABLE IF NOT EXISTS controllers_ctl (
|
||||
id text NOT NULL PRIMARY KEY,
|
||||
hostname text,
|
||||
last_heartbeat timestamp with time zone,
|
||||
public_identity text NOT NULL,
|
||||
version text
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS networks_ctl (
|
||||
id character varying(22) NOT NULL PRIMARY KEY,
|
||||
name text NOT NULL,
|
||||
configuration jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
controller_id text REFERENCES controllers_ctl(id),
|
||||
revision integer DEFAULT 0 NOT NULL,
|
||||
last_modified timestamp with time zone DEFAULT now(),
|
||||
creation_time timestamp with time zone DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS network_memberships_ctl (
|
||||
device_id character varying(22) NOT NULL,
|
||||
network_id character varying(22) NOT NULL REFERENCES networks_ctl(id),
|
||||
authorized boolean,
|
||||
active_bridge boolean,
|
||||
ip_assignments text[],
|
||||
no_auto_assign_ips boolean,
|
||||
sso_exempt boolean,
|
||||
authentication_expiry_time timestamp with time zone,
|
||||
capabilities jsonb,
|
||||
creation_time timestamp with time zone DEFAULT now(),
|
||||
last_modified timestamp with time zone DEFAULT now(),
|
||||
identity text DEFAULT ''::text,
|
||||
last_authorized_credential text,
|
||||
last_authorized_time timestamp with time zone,
|
||||
last_deauthorized_time timestamp with time zone,
|
||||
last_seen jsonb DEFAULT '{}'::jsonb NOT NULL, -- in the context of the network
|
||||
remote_trace_level integer DEFAULT 0 NOT NULL,
|
||||
remote_trace_target text DEFAULT ''::text NOT NULL,
|
||||
revision integer DEFAULT 0 NOT NULL,
|
||||
tags jsonb,
|
||||
version_major integer DEFAULT 0 NOT NULL,
|
||||
version_minor integer DEFAULT 0 NOT NULL,
|
||||
version_revision integer DEFAULT 0 NOT NULL,
|
||||
version_protocol integer DEFAULT 0 NOT NULL,
|
||||
PRIMARY KEY (device_id, network_id)
|
||||
);
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE network_memberships_ctl
|
||||
DROP COLUMN os,
|
||||
DROP COLUMN arch;
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE network_memberships_ctl
|
||||
ADD COLUMN os TEXT NOT NULL DEFAULT 'unknown',
|
||||
ADD COLUMN arch TEXT NOT NULL DEFAULT 'unknown';
|
|
@ -431,6 +431,10 @@ central-controller-docker: _buildx FORCE
|
|||
docker buildx build --platform linux/amd64,linux/arm64 --no-cache -t registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=`git name-rev --name-only HEAD` . --push
|
||||
@echo Image: registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP}
|
||||
|
||||
centralv2-controller-docker: _buildx FORCE
|
||||
docker buildx build --platform linux/amd64,linux/arm64 --no-cache -t us-central1-docker.pkg.dev/zerotier-d648c7/central-v2/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=`git name-rev --name-only HEAD` . --push
|
||||
@echo Image: us-central1-docker.pkg.dev/zerotier-d648c7/central-v2/ztcentral-controller:${TIMESTAMP}
|
||||
|
||||
debug: FORCE
|
||||
make ZT_DEBUG=1 one
|
||||
make ZT_DEBUG=1 selftest
|
||||
|
|
21
make-mac.mk
21
make-mac.mk
|
@ -57,9 +57,9 @@ ONE_OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ext/miniupnpc/connec
|
|||
ifeq ($(ZT_CONTROLLER),1)
|
||||
MACOS_VERSION_MIN=10.15
|
||||
override CXXFLAGS=$(CFLAGS) -std=c++17 -stdlib=libc++
|
||||
LIBS+=-L/usr/local/opt/libpqxx/lib -L/usr/local/opt/libpq/lib -L/usr/local/opt/openssl/lib/ -lpqxx -lpq -lssl -lcrypto -lgssapi_krb5 ext/redis-plus-plus-1.1.1/install/macos/lib/libredis++.a ext/hiredis-0.14.1/lib/macos/libhiredis.a
|
||||
LIBS+=-L/opt/homebrew/lib -L/usr/local/opt/libpqxx/lib -L/usr/local/opt/libpq/lib -L/usr/local/opt/openssl/lib/ -lpqxx -lpq -lssl -lcrypto -lgssapi_krb5 ext/redis-plus-plus-1.1.1/install/macos/lib/libredis++.a ext/hiredis-0.14.1/lib/macos/libhiredis.a rustybits/target/libsmeeclient.a
|
||||
DEFS+=-DZT_CONTROLLER_USE_LIBPQ -DZT_CONTROLLER_USE_REDIS -DZT_CONTROLLER
|
||||
INCLUDES+=-I/usr/local/opt/libpq/include -I/usr/local/opt/libpqxx/include -Iext/hiredis-0.14.1/include/ -Iext/redis-plus-plus-1.1.1/install/macos/include/sw/
|
||||
INCLUDES+=-I/opt/homebrew/include -I/opt/homebrew/opt/libpq/include -I/usr/local/opt/libpq/include -I/usr/local/opt/libpqxx/include -Iext/hiredis-0.14.1/include/ -Iext/redis-plus-plus-1.1.1/install/macos/include/sw/ -Irustybits/target/
|
||||
else
|
||||
MACOS_VERSION_MIN=10.13
|
||||
endif
|
||||
|
@ -115,7 +115,11 @@ mac-agent: FORCE
|
|||
osdep/MacDNSHelper.o: osdep/MacDNSHelper.mm
|
||||
$(CXX) $(CXXFLAGS) -c osdep/MacDNSHelper.mm -o osdep/MacDNSHelper.o
|
||||
|
||||
ifeq ($(ZT_CONTROLLER),1)
|
||||
one: zeroidc smeeclient $(CORE_OBJS) $(ONE_OBJS) one.o mac-agent
|
||||
else
|
||||
one: zeroidc $(CORE_OBJS) $(ONE_OBJS) one.o mac-agent
|
||||
endif
|
||||
$(CXX) $(CXXFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS) rustybits/target/libzeroidc.a
|
||||
# $(STRIP) zerotier-one
|
||||
ln -sf zerotier-one zerotier-idtool
|
||||
|
@ -126,6 +130,15 @@ zerotier-one: one
|
|||
|
||||
zeroidc: rustybits/target/libzeroidc.a
|
||||
|
||||
ifeq ($(ZT_CONTROLLER),1)
|
||||
smeeclient: rustybits/target/libsmeeclient.a
|
||||
|
||||
rustybits/target/libsmeeclient.a: FORCE
|
||||
cd rustybits && MACOSX_DEPLOYMENT_TARGET=$(MACOS_VERSION_MIN) cargo build -p smeeclient --target=x86_64-apple-darwin $(EXTRA_CARGO_FLAGS)
|
||||
cd rustybits && MACOSX_DEPLOYMENT_TARGET=$(MACOS_VERSION_MIN) cargo build -p smeeclient --target=aarch64-apple-darwin $(EXTRA_CARGO_FLAGS)
|
||||
cd rustybits && lipo -create target/x86_64-apple-darwin/$(RUST_VARIANT)/libsmeeclient.a target/aarch64-apple-darwin/$(RUST_VARIANT)/libsmeeclient.a -output target/libsmeeclient.a
|
||||
endif
|
||||
|
||||
rustybits/target/libzeroidc.a: FORCE
|
||||
cd rustybits && MACOSX_DEPLOYMENT_TARGET=$(MACOS_VERSION_MIN) cargo build -p zeroidc --target=x86_64-apple-darwin $(EXTRA_CARGO_FLAGS)
|
||||
cd rustybits && MACOSX_DEPLOYMENT_TARGET=$(MACOS_VERSION_MIN) cargo build -p zeroidc --target=aarch64-apple-darwin $(EXTRA_CARGO_FLAGS)
|
||||
|
@ -195,6 +208,10 @@ central-controller-docker: _buildx FORCE
|
|||
docker buildx build --platform linux/arm64,linux/amd64 --no-cache -t registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=$(shell git name-rev --name-only HEAD) . --push
|
||||
@echo Image: registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP}
|
||||
|
||||
centralv2-controller-docker: _buildx FORCE
|
||||
docker buildx build --platform linux/amd64,linux/arm64 --no-cache -t us-central1-docker.pkg.dev/zerotier-d648c7/central-v2/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=`git name-rev --name-only HEAD` . --push
|
||||
@echo Image: us-central1-docker.pkg.dev/zerotier-d648c7/central-v2/ztcentral-controller:${TIMESTAMP}
|
||||
|
||||
docker-release: _buildx
|
||||
docker buildx build --platform linux/386,linux/amd64,linux/arm/v7,linux/arm64,linux/mips64le,linux/ppc64le,linux/s390x -t zerotier/zerotier:${RELEASE_DOCKER_TAG} -t zerotier/zerotier:latest --build-arg VERSION=${RELEASE_VERSION} -f Dockerfile.release . --push
|
||||
|
||||
|
|
|
@ -39,7 +39,10 @@ ONE_OBJS=\
|
|||
controller/DB.o \
|
||||
controller/FileDB.o \
|
||||
controller/LFDB.o \
|
||||
controller/CtlUtil.o \
|
||||
controller/PostgreSQL.o \
|
||||
controller/CV1.o \
|
||||
controller/CV2.o \
|
||||
osdep/EthernetTap.o \
|
||||
osdep/ManagedRoute.o \
|
||||
osdep/Http.o \
|
||||
|
|
Loading…
Add table
Reference in a new issue