mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-26 17:03:43 +02:00
Add serialize and deserialize functions to TrustStore.
This commit is contained in:
parent
38fcefceee
commit
0f4d18c4ed
6 changed files with 145 additions and 26 deletions
|
@ -60,8 +60,6 @@ namespace {
|
||||||
// #define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */
|
// #define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */
|
||||||
// #define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */
|
// #define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */
|
||||||
#define LZ4_MEMORY_USAGE 14
|
#define LZ4_MEMORY_USAGE 14
|
||||||
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
|
|
||||||
#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
|
|
||||||
|
|
||||||
typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */
|
typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
#define LZ4_MAX_INPUT_SIZE 0x7E000000
|
||||||
|
#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
|
||||||
|
|
||||||
int LZ4_compress_fast(const char *source,char *dest,int inputSize,int maxOutputSize,int acceleration = 1) noexcept;
|
int LZ4_compress_fast(const char *source,char *dest,int inputSize,int maxOutputSize,int acceleration = 1) noexcept;
|
||||||
int LZ4_decompress_safe(const char *source,char *dest,int compressedSize,int maxDecompressedSize) noexcept;
|
int LZ4_decompress_safe(const char *source,char *dest,int compressedSize,int maxDecompressedSize) noexcept;
|
||||||
|
|
||||||
|
|
|
@ -143,10 +143,10 @@ Node::~Node()
|
||||||
{
|
{
|
||||||
ZT_SPEW("Node shutting down (in destructor).");
|
ZT_SPEW("Node shutting down (in destructor).");
|
||||||
|
|
||||||
m_networks_l.lock();
|
m_allNetworks_l.lock();
|
||||||
RR->networks->clear();
|
RR->networks->clear();
|
||||||
m_networks.clear();
|
m_allNetworks.clear();
|
||||||
m_networks_l.unlock();
|
m_allNetworks_l.unlock();
|
||||||
|
|
||||||
delete reinterpret_cast<_NodeObjects *>(m_objects);
|
delete reinterpret_cast<_NodeObjects *>(m_objects);
|
||||||
|
|
||||||
|
@ -159,10 +159,10 @@ Node::~Node()
|
||||||
|
|
||||||
void Node::shutdown(void *tPtr)
|
void Node::shutdown(void *tPtr)
|
||||||
{
|
{
|
||||||
m_networks_l.lock();
|
m_allNetworks_l.lock();
|
||||||
RR->networks->clear();
|
RR->networks->clear();
|
||||||
m_networks.clear();
|
m_allNetworks.clear();
|
||||||
m_networks_l.unlock();
|
m_allNetworks_l.unlock();
|
||||||
postEvent(tPtr, ZT_EVENT_DOWN);
|
postEvent(tPtr, ZT_EVENT_DOWN);
|
||||||
if (RR->topology)
|
if (RR->topology)
|
||||||
RR->topology->saveAll(tPtr);
|
RR->topology->saveAll(tPtr);
|
||||||
|
@ -201,8 +201,8 @@ ZT_ResultCode Node::processBackgroundTasks(
|
||||||
if ((now - m_lastNetworkHousekeepingRun) >= ZT_NETWORK_HOUSEKEEPING_PERIOD) {
|
if ((now - m_lastNetworkHousekeepingRun) >= ZT_NETWORK_HOUSEKEEPING_PERIOD) {
|
||||||
m_lastHousekeepingRun = now;
|
m_lastHousekeepingRun = now;
|
||||||
ZT_SPEW("running networking housekeeping...");
|
ZT_SPEW("running networking housekeeping...");
|
||||||
Mutex::Lock l(m_networks_l);
|
Mutex::Lock l(m_allNetworks_l);
|
||||||
for (Vector< SharedPtr< Network > >::const_iterator i(m_networks.begin()); i != m_networks.end(); ++i) {
|
for (Vector< SharedPtr< Network > >::const_iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i) {
|
||||||
(*i)->doPeriodicTasks(tPtr, now);
|
(*i)->doPeriodicTasks(tPtr, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ ZT_ResultCode Node::join(
|
||||||
void *uptr,
|
void *uptr,
|
||||||
void *tptr)
|
void *tptr)
|
||||||
{
|
{
|
||||||
Mutex::Lock l(m_networks_l);
|
Mutex::Lock l(m_allNetworks_l);
|
||||||
|
|
||||||
Fingerprint fp;
|
Fingerprint fp;
|
||||||
if (controllerFingerprint) {
|
if (controllerFingerprint) {
|
||||||
|
@ -245,12 +245,12 @@ ZT_ResultCode Node::join(
|
||||||
ZT_SPEW("joining network %.16llx", nwid);
|
ZT_SPEW("joining network %.16llx", nwid);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Vector< SharedPtr< Network > >::iterator n(m_networks.begin()); n != m_networks.end(); ++n) {
|
for (Vector< SharedPtr< Network > >::iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) {
|
||||||
if ((*n)->id() == nwid)
|
if ((*n)->id() == nwid)
|
||||||
return ZT_RESULT_OK;
|
return ZT_RESULT_OK;
|
||||||
}
|
}
|
||||||
SharedPtr< Network > network(new Network(RR, tptr, nwid, fp, uptr, nullptr));
|
SharedPtr< Network > network(new Network(RR, tptr, nwid, fp, uptr, nullptr));
|
||||||
m_networks.push_back(network);
|
m_allNetworks.push_back(network);
|
||||||
RR->networks->set(nwid, network);
|
RR->networks->set(nwid, network);
|
||||||
|
|
||||||
return ZT_RESULT_OK;
|
return ZT_RESULT_OK;
|
||||||
|
@ -261,17 +261,17 @@ ZT_ResultCode Node::leave(
|
||||||
void **uptr,
|
void **uptr,
|
||||||
void *tptr)
|
void *tptr)
|
||||||
{
|
{
|
||||||
Mutex::Lock l(m_networks_l);
|
Mutex::Lock l(m_allNetworks_l);
|
||||||
|
|
||||||
ZT_SPEW("leaving network %.16llx", nwid);
|
ZT_SPEW("leaving network %.16llx", nwid);
|
||||||
ZT_VirtualNetworkConfig ctmp;
|
ZT_VirtualNetworkConfig ctmp;
|
||||||
|
|
||||||
SharedPtr< Network > network;
|
SharedPtr< Network > network;
|
||||||
RR->networks->erase(nwid);
|
RR->networks->erase(nwid);
|
||||||
for (Vector< SharedPtr< Network > >::iterator n(m_networks.begin()); n != m_networks.end(); ++n) {
|
for (Vector< SharedPtr< Network > >::iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) {
|
||||||
if ((*n)->id() == nwid) {
|
if ((*n)->id() == nwid) {
|
||||||
network.move(*n);
|
network.move(*n);
|
||||||
m_networks.erase(n);
|
m_allNetworks.erase(n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,9 +452,9 @@ ZT_VirtualNetworkConfig *Node::networkConfig(uint64_t nwid) const
|
||||||
|
|
||||||
ZT_VirtualNetworkList *Node::networks() const
|
ZT_VirtualNetworkList *Node::networks() const
|
||||||
{
|
{
|
||||||
Mutex::Lock l(m_networks_l);
|
Mutex::Lock l(m_allNetworks_l);
|
||||||
|
|
||||||
char *const buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * m_networks.size()));
|
char *const buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * m_allNetworks.size()));
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf;
|
ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf;
|
||||||
|
@ -462,7 +462,7 @@ ZT_VirtualNetworkList *Node::networks() const
|
||||||
nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList));
|
nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList));
|
||||||
|
|
||||||
nl->networkCount = 0;
|
nl->networkCount = 0;
|
||||||
for (Vector< SharedPtr< Network > >::const_iterator i(m_networks.begin()); i != m_networks.end(); ++i)
|
for (Vector< SharedPtr< Network > >::const_iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i)
|
||||||
(*i)->externalConfig(&(nl->networks[nl->networkCount++]));
|
(*i)->externalConfig(&(nl->networks[nl->networkCount++]));
|
||||||
|
|
||||||
return nl;
|
return nl;
|
||||||
|
@ -474,9 +474,9 @@ void Node::setNetworkUserPtr(
|
||||||
{
|
{
|
||||||
SharedPtr< Network > nw(RR->networks->get(nwid));
|
SharedPtr< Network > nw(RR->networks->get(nwid));
|
||||||
if (nw) {
|
if (nw) {
|
||||||
m_networks_l.lock(); // ensure no concurrent modification of user PTR in network
|
m_allNetworks_l.lock(); // ensure no concurrent modification of user PTR in network
|
||||||
*(nw->userPtr()) = ptr;
|
*(nw->userPtr()) = ptr;
|
||||||
m_networks_l.unlock();
|
m_allNetworks_l.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,8 +639,8 @@ void Node::setController(void *networkControllerInstance)
|
||||||
bool Node::shouldUsePathForZeroTierTraffic(void *tPtr, const Identity &id, const int64_t localSocket, const InetAddress &remoteAddress)
|
bool Node::shouldUsePathForZeroTierTraffic(void *tPtr, const Identity &id, const int64_t localSocket, const InetAddress &remoteAddress)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Mutex::Lock l(m_networks_l);
|
Mutex::Lock l(m_allNetworks_l);
|
||||||
for (Vector< SharedPtr< Network > >::iterator i(m_networks.begin()); i != m_networks.end(); ++i) {
|
for (Vector< SharedPtr< Network > >::iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i) {
|
||||||
for (unsigned int k = 0, j = (*i)->config().staticIpCount; k < j; ++k) {
|
for (unsigned int k = 0, j = (*i)->config().staticIpCount; k < j; ++k) {
|
||||||
if ((*i)->config().staticIps[k].containsAddress(remoteAddress))
|
if ((*i)->config().staticIps[k].containsAddress(remoteAddress))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -218,9 +218,9 @@ private:
|
||||||
// Pointer to a struct defined in Node that holds instances of core objects.
|
// Pointer to a struct defined in Node that holds instances of core objects.
|
||||||
void *m_objects;
|
void *m_objects;
|
||||||
|
|
||||||
// This isn't the primary network lookup but holds a vector of networks for rapid iteration through all of them.
|
// This stores networks for rapid iteration, while RR->networks is the primary lookup.
|
||||||
Vector< SharedPtr< Network > > m_networks;
|
Vector< SharedPtr< Network > > m_allNetworks;
|
||||||
Mutex m_networks_l;
|
Mutex m_allNetworks_l;
|
||||||
|
|
||||||
// These are local interface addresses that have been configured via the API
|
// These are local interface addresses that have been configured via the API
|
||||||
// and can be pushed to other nodes.
|
// and can be pushed to other nodes.
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
#include "TrustStore.hpp"
|
#include "TrustStore.hpp"
|
||||||
|
#include "LZ4.hpp"
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
@ -223,4 +224,103 @@ void TrustStore::update(const int64_t clock, Vector< SharedPtr< Entry > > *const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector< uint8_t > TrustStore::save() const
|
||||||
|
{
|
||||||
|
Vector< uint8_t> comp;
|
||||||
|
|
||||||
|
int compSize;
|
||||||
|
{
|
||||||
|
Vector< uint8_t > b;
|
||||||
|
b.reserve(65536);
|
||||||
|
|
||||||
|
RWMutex::RLock l(m_lock);
|
||||||
|
|
||||||
|
b.push_back(0); // version byte
|
||||||
|
|
||||||
|
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
|
||||||
|
const Vector< uint8_t > cdata(c->second->certificate().encode());
|
||||||
|
if (!cdata.empty()) {
|
||||||
|
const uint32_t localTrust = (uint32_t)c->second->localTrust();
|
||||||
|
b.push_back((uint8_t)(localTrust >> 24U));
|
||||||
|
b.push_back((uint8_t)(localTrust >> 16U));
|
||||||
|
b.push_back((uint8_t)(localTrust >> 8U));
|
||||||
|
b.push_back((uint8_t)localTrust);
|
||||||
|
const uint32_t size = (uint32_t)cdata.size();
|
||||||
|
b.push_back((uint8_t)(size >> 24U));
|
||||||
|
b.push_back((uint8_t)(size >> 16U));
|
||||||
|
b.push_back((uint8_t)(size >> 8U));
|
||||||
|
b.push_back((uint8_t)size);
|
||||||
|
b.insert(b.end(), cdata.begin(), cdata.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
comp.resize((unsigned long)LZ4_COMPRESSBOUND(b.size()) + 8);
|
||||||
|
compSize = LZ4_compress_fast(reinterpret_cast<const char *>(b.data()), reinterpret_cast<char *>(comp.data() + 8), (int)b.size(), (int)(comp.size() - 8));
|
||||||
|
if (unlikely(compSize <= 0)) // shouldn't be possible
|
||||||
|
return Vector< uint8_t >();
|
||||||
|
|
||||||
|
const uint32_t uncompSize = (uint32_t)b.size();
|
||||||
|
const uint32_t cksum = Utils::fnv1a32(b.data(), (unsigned int)uncompSize);
|
||||||
|
comp[0] = (uint8_t)(uncompSize >> 24);
|
||||||
|
comp[1] = (uint8_t)(uncompSize >> 16);
|
||||||
|
comp[2] = (uint8_t)(uncompSize >> 8);
|
||||||
|
comp[3] = (uint8_t)uncompSize;
|
||||||
|
comp[4] = (uint8_t)(cksum >> 24);
|
||||||
|
comp[5] = (uint8_t)(cksum >> 16);
|
||||||
|
comp[6] = (uint8_t)(cksum >> 8);
|
||||||
|
comp[7] = (uint8_t)cksum;
|
||||||
|
compSize += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
comp.resize((unsigned long)compSize);
|
||||||
|
comp.shrink_to_fit();
|
||||||
|
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TrustStore::load(const Vector< uint8_t > &data)
|
||||||
|
{
|
||||||
|
if (data.size() < 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
const unsigned long uncompSize = Utils::loadBigEndian<uint32_t>(data.data());
|
||||||
|
if (uncompSize > (data.size() * 256)) // sanity check
|
||||||
|
return -1;
|
||||||
|
if (uncompSize < 1) // no room for at least version and count
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
Vector< uint8_t > uncomp;
|
||||||
|
uncomp.resize(uncompSize);
|
||||||
|
|
||||||
|
if (LZ4_decompress_safe(reinterpret_cast<const char *>(data.data() + 8), reinterpret_cast<char *>(uncomp.data()), (int)(data.size() - 8), (int)uncompSize) != (int)uncompSize)
|
||||||
|
return -1;
|
||||||
|
const uint8_t *b = uncomp.data();
|
||||||
|
if (Utils::fnv1a32(b, (unsigned int)uncompSize) != Utils::loadBigEndian<uint32_t>(data.data() + 4))
|
||||||
|
return -1;
|
||||||
|
const uint8_t *const eof = b + uncompSize;
|
||||||
|
|
||||||
|
if (*(b++) != 0) // unrecognized version
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int readCount = 0;
|
||||||
|
for(;;) {
|
||||||
|
if ((b + 8) > eof)
|
||||||
|
break;
|
||||||
|
const uint32_t localTrust = Utils::loadBigEndian<uint32_t>(b);
|
||||||
|
b += 4;
|
||||||
|
const uint32_t cdataSize = Utils::loadBigEndian<uint32_t>(b);
|
||||||
|
b += 4;
|
||||||
|
|
||||||
|
if ((b + cdataSize) > eof)
|
||||||
|
break;
|
||||||
|
Certificate c;
|
||||||
|
if (c.decode(b, (unsigned int)cdataSize)) {
|
||||||
|
this->add(c, (unsigned int)localTrust);
|
||||||
|
++readCount;
|
||||||
|
}
|
||||||
|
b += cdataSize;
|
||||||
|
}
|
||||||
|
return readCount;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -164,6 +164,24 @@ public:
|
||||||
*/
|
*/
|
||||||
void update(int64_t clock, Vector< SharedPtr< Entry > > *purge);
|
void update(int64_t clock, Vector< SharedPtr< Entry > > *purge);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a compressed binary version of certificates and their local trust
|
||||||
|
*
|
||||||
|
* @return Binary compressed certificates and local trust info
|
||||||
|
*/
|
||||||
|
Vector< uint8_t > save() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode a saved trust store
|
||||||
|
*
|
||||||
|
* Decoded certificates are added to the add queue, so update() must be
|
||||||
|
* called after this to actually apply them.
|
||||||
|
*
|
||||||
|
* @param data Data to decode
|
||||||
|
* @return Number of certificates or -1 if input is invalid
|
||||||
|
*/
|
||||||
|
int load(const Vector< uint8_t > &data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Map< H384, SharedPtr< Entry > > m_bySerial; // all certificates
|
Map< H384, SharedPtr< Entry > > m_bySerial; // all certificates
|
||||||
Map< Vector< uint8_t >, SharedPtr< Entry > > m_bySubjectUniqueId; // non-rejected certificates only
|
Map< Vector< uint8_t >, SharedPtr< Entry > > m_bySubjectUniqueId; // non-rejected certificates only
|
||||||
|
|
Loading…
Add table
Reference in a new issue