Browse Source
# Conflicts: # controller/DB.hpp # controller/DBMirrorSet.cpp # controller/DBMirrorSet.hpp # controller/EmbeddedNetworkController.cpp # controller/FileDB.cpp # controller/FileDB.hpp # controller/LFDB.cpp # controller/LFDB.hpp # controller/PostgreSQL.cpp # controller/PostgreSQL.hpp # node/C25519.cpp # node/C25519.hpp # node/Capability.hpp # node/CertificateOfMembership.cpp # node/CertificateOfMembership.hpp # node/CertificateOfOwnership.hpp # node/Credential.hpp # node/Identity.cpp # node/Identity.hpp # node/IncomingPacket.cpp # node/Metrics.cpp # node/Metrics.hpp # node/Multicaster.cpp # node/Network.cpp # node/Node.cpp # node/Packet.cpp # node/Packet.hpp # node/Peer.cpp # node/Revocation.hpp # node/Switch.cpp # node/Tag.hpp # node/World.hpp # osdep/Http.hpp # service/OneService.cpppull/4/head
32 changed files with 3589 additions and 2164 deletions
@ -0,0 +1,141 @@ |
|||||||
|
/*
|
||||||
|
* 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 "../node/Metrics.hpp" |
||||||
|
#include "ConnectionPool.hpp" |
||||||
|
#include "PostgreSQL.hpp" |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
#include <pqxx/pqxx> |
||||||
|
#include <redis++/redis++.h> |
||||||
|
|
||||||
|
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
|
||||||
@ -0,0 +1,112 @@ |
|||||||
|
/*
|
||||||
|
* 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 "../node/Metrics.hpp" |
||||||
|
#include "ConnectionPool.hpp" |
||||||
|
#include "PostgreSQL.hpp" |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
#include <pqxx/pqxx> |
||||||
|
#include <redis++/redis++.h> |
||||||
|
|
||||||
|
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
|
||||||
@ -0,0 +1,64 @@ |
|||||||
|
#include "CtlUtil.hpp" |
||||||
|
|
||||||
|
#ifdef ZT_CONTROLLER_USE_LIBPQ |
||||||
|
|
||||||
|
#include <iomanip> |
||||||
|
#include <sstream> |
||||||
|
|
||||||
|
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 |
||||||
@ -0,0 +1,16 @@ |
|||||||
|
#ifndef ZT_CTLUTIL_HPP |
||||||
|
#define ZT_CTLUTIL_HPP |
||||||
|
|
||||||
|
#include <string> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
namespace ZeroTier { |
||||||
|
|
||||||
|
const char* _timestr(); |
||||||
|
|
||||||
|
std::vector<std::string> split(std::string str, char delim); |
||||||
|
|
||||||
|
std::string url_encode(const std::string& value); |
||||||
|
} // namespace ZeroTier
|
||||||
|
|
||||||
|
#endif // namespace ZeroTier
|
||||||
@ -1,15 +1,17 @@ |
|||||||
FROM ubuntu:jammy |
FROM debian:bookworm |
||||||
|
|
||||||
|
|
||||||
RUN apt update && apt upgrade -y |
|
||||||
|
|
||||||
|
RUN apt update && apt upgrade -y |
||||||
RUN apt -y install \ |
RUN apt -y install \ |
||||||
netcat \ |
netcat-traditional \ |
||||||
postgresql-client \ |
postgresql-client \ |
||||||
postgresql-client-common \ |
postgresql-client-common \ |
||||||
libjemalloc2 \ |
libjemalloc2 \ |
||||||
libpq5 \ |
libpq5 \ |
||||||
curl \ |
curl \ |
||||||
binutils \ |
binutils \ |
||||||
linux-tools-gke \ |
|
||||||
perf-tools-unstable \ |
perf-tools-unstable \ |
||||||
google-perftools |
google-perftools \ |
||||||
|
gnupg |
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,3 @@ |
|||||||
|
DROP TABLE IF EXISTS network_memberships_ctl; |
||||||
|
DROP TABLE IF EXISTS networks_ctl; |
||||||
|
DROP TABLE IF EXISTS controllers_ctl; |
||||||
@ -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'; |
||||||
Loading…
Reference in new issue