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_RELEASE 5 /* for tweaks, bug-fixes, or development */
|
||||
#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) */
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
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_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).");
|
||||
|
||||
m_networks_l.lock();
|
||||
m_allNetworks_l.lock();
|
||||
RR->networks->clear();
|
||||
m_networks.clear();
|
||||
m_networks_l.unlock();
|
||||
m_allNetworks.clear();
|
||||
m_allNetworks_l.unlock();
|
||||
|
||||
delete reinterpret_cast<_NodeObjects *>(m_objects);
|
||||
|
||||
|
@ -159,10 +159,10 @@ Node::~Node()
|
|||
|
||||
void Node::shutdown(void *tPtr)
|
||||
{
|
||||
m_networks_l.lock();
|
||||
m_allNetworks_l.lock();
|
||||
RR->networks->clear();
|
||||
m_networks.clear();
|
||||
m_networks_l.unlock();
|
||||
m_allNetworks.clear();
|
||||
m_allNetworks_l.unlock();
|
||||
postEvent(tPtr, ZT_EVENT_DOWN);
|
||||
if (RR->topology)
|
||||
RR->topology->saveAll(tPtr);
|
||||
|
@ -201,8 +201,8 @@ ZT_ResultCode Node::processBackgroundTasks(
|
|||
if ((now - m_lastNetworkHousekeepingRun) >= ZT_NETWORK_HOUSEKEEPING_PERIOD) {
|
||||
m_lastHousekeepingRun = now;
|
||||
ZT_SPEW("running networking housekeeping...");
|
||||
Mutex::Lock l(m_networks_l);
|
||||
for (Vector< SharedPtr< Network > >::const_iterator i(m_networks.begin()); i != m_networks.end(); ++i) {
|
||||
Mutex::Lock l(m_allNetworks_l);
|
||||
for (Vector< SharedPtr< Network > >::const_iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i) {
|
||||
(*i)->doPeriodicTasks(tPtr, now);
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ ZT_ResultCode Node::join(
|
|||
void *uptr,
|
||||
void *tptr)
|
||||
{
|
||||
Mutex::Lock l(m_networks_l);
|
||||
Mutex::Lock l(m_allNetworks_l);
|
||||
|
||||
Fingerprint fp;
|
||||
if (controllerFingerprint) {
|
||||
|
@ -245,12 +245,12 @@ ZT_ResultCode Node::join(
|
|||
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)
|
||||
return ZT_RESULT_OK;
|
||||
}
|
||||
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);
|
||||
|
||||
return ZT_RESULT_OK;
|
||||
|
@ -261,17 +261,17 @@ ZT_ResultCode Node::leave(
|
|||
void **uptr,
|
||||
void *tptr)
|
||||
{
|
||||
Mutex::Lock l(m_networks_l);
|
||||
Mutex::Lock l(m_allNetworks_l);
|
||||
|
||||
ZT_SPEW("leaving network %.16llx", nwid);
|
||||
ZT_VirtualNetworkConfig ctmp;
|
||||
|
||||
SharedPtr< Network > network;
|
||||
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) {
|
||||
network.move(*n);
|
||||
m_networks.erase(n);
|
||||
m_allNetworks.erase(n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -452,9 +452,9 @@ ZT_VirtualNetworkConfig *Node::networkConfig(uint64_t nwid) 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)
|
||||
return nullptr;
|
||||
ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf;
|
||||
|
@ -462,7 +462,7 @@ ZT_VirtualNetworkList *Node::networks() const
|
|||
nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList));
|
||||
|
||||
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++]));
|
||||
|
||||
return nl;
|
||||
|
@ -474,9 +474,9 @@ void Node::setNetworkUserPtr(
|
|||
{
|
||||
SharedPtr< Network > nw(RR->networks->get(nwid));
|
||||
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;
|
||||
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)
|
||||
{
|
||||
{
|
||||
Mutex::Lock l(m_networks_l);
|
||||
for (Vector< SharedPtr< Network > >::iterator i(m_networks.begin()); i != m_networks.end(); ++i) {
|
||||
Mutex::Lock l(m_allNetworks_l);
|
||||
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) {
|
||||
if ((*i)->config().staticIps[k].containsAddress(remoteAddress))
|
||||
return false;
|
||||
|
|
|
@ -218,9 +218,9 @@ private:
|
|||
// Pointer to a struct defined in Node that holds instances of core objects.
|
||||
void *m_objects;
|
||||
|
||||
// This isn't the primary network lookup but holds a vector of networks for rapid iteration through all of them.
|
||||
Vector< SharedPtr< Network > > m_networks;
|
||||
Mutex m_networks_l;
|
||||
// This stores networks for rapid iteration, while RR->networks is the primary lookup.
|
||||
Vector< SharedPtr< Network > > m_allNetworks;
|
||||
Mutex m_allNetworks_l;
|
||||
|
||||
// These are local interface addresses that have been configured via the API
|
||||
// and can be pushed to other nodes.
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
/****/
|
||||
|
||||
#include "TrustStore.hpp"
|
||||
#include "LZ4.hpp"
|
||||
|
||||
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
|
||||
|
|
|
@ -164,6 +164,24 @@ public:
|
|||
*/
|
||||
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:
|
||||
Map< H384, SharedPtr< Entry > > m_bySerial; // all certificates
|
||||
Map< Vector< uint8_t >, SharedPtr< Entry > > m_bySubjectUniqueId; // non-rejected certificates only
|
||||
|
|
Loading…
Add table
Reference in a new issue