mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-08 11:44:13 +00:00
TON of refactoring, moon/planet is DEAD, ECC P-384 is integrated (but not enabled), and multicast work and cleanup. Whew.
This commit is contained in:
parent
640bbaabbf
commit
fe2215df00
@ -1,162 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2019 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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_MTUDPSOCKET_HPP
|
||||
#define ZT_MTUDPSOCKET_HPP
|
||||
|
||||
#ifndef __WINDOWS__
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../include/ZeroTierOne.h"
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
#include "../osdep/Thread.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* MTUDPSocket is a multithreaded UDP socket using multiple binds and SO_REUSEPORT
|
||||
*
|
||||
* On Mac and Linux this is the most efficient way to implement a multithreaded UDP
|
||||
* I/O path. On Windows it's probably not necessary to optimize this much. If it ever
|
||||
* is, we will have to implement a version of this the Windows way.
|
||||
*/
|
||||
class MTUDPSocket
|
||||
{
|
||||
public:
|
||||
inline MTUDPSocket(ZT_Node *n,volatile int64_t *dptr,const struct sockaddr *bindAddr)
|
||||
{
|
||||
const int ncores = std::max(1,(int)sysconf(_SC_NPROCESSORS_CONF));
|
||||
for(int t=0;t<ncores;t++) {
|
||||
int s = socket(bindAddr->sa_family,SOCK_DGRAM,0);
|
||||
if (s < 0) {
|
||||
for(auto i=_sockets.begin();i!=_sockets.end();++i)
|
||||
close(*i);
|
||||
throw std::runtime_error("unable to allocate socket");
|
||||
}
|
||||
|
||||
int f = 131072;
|
||||
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char *)&f,sizeof(f));
|
||||
f = 131072;
|
||||
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char *)&f,sizeof(f));
|
||||
|
||||
if (bindAddr->sa_family == AF_INET6) {
|
||||
f = 1; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f));
|
||||
#ifdef IPV6_MTU_DISCOVER
|
||||
f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_MTU_DISCOVER,&f,sizeof(f));
|
||||
#endif
|
||||
#ifdef IPV6_DONTFRAG
|
||||
f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,&f,sizeof(f));
|
||||
#endif
|
||||
}
|
||||
f = 1; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
|
||||
f = 1; setsockopt(s,SOL_SOCKET,SO_REUSEPORT,(void *)&f,sizeof(f));
|
||||
f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f));
|
||||
#ifdef IP_DONTFRAG
|
||||
f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f));
|
||||
#endif
|
||||
#ifdef IP_MTU_DISCOVER
|
||||
f = 0; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f));
|
||||
#endif
|
||||
#ifdef SO_NO_CHECK
|
||||
if (bindAddr->sa_family == AF_INET) {
|
||||
f = 1; setsockopt(s,SOL_SOCKET,SO_NO_CHECK,(void *)&f,sizeof(f));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bind(s,bindAddr,(bindAddr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))) {
|
||||
for(auto i=_sockets.begin();i!=_sockets.end();++i)
|
||||
close(*i);
|
||||
throw std::runtime_error("unable to bind to address");
|
||||
}
|
||||
|
||||
_sockets.push_back(s);
|
||||
}
|
||||
|
||||
for(auto s=_sockets.begin();s!=_sockets.end();++s) {
|
||||
try {
|
||||
new MTUDPThread(n,dptr,*s);
|
||||
} catch ( ... ) {
|
||||
for(auto i=_sockets.begin();i!=_sockets.end();++i)
|
||||
close(*i);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline ~MTUDPSocket()
|
||||
{
|
||||
for(auto i=_sockets.begin();i!=_sockets.end();++i)
|
||||
close(*i);
|
||||
}
|
||||
|
||||
private:
|
||||
class MTUDPThread
|
||||
{
|
||||
public:
|
||||
inline MTUDPThread(ZT_Node *n,volatile int64_t *dptr,int s) :
|
||||
node(n),
|
||||
deadlinePtr(dptr),
|
||||
sock(s),
|
||||
thread(Thread::start(this))
|
||||
{
|
||||
}
|
||||
|
||||
inline void threadMain()
|
||||
{
|
||||
struct sockaddr_storage from;
|
||||
for(;;) {
|
||||
socklen_t fromLen = sizeof(from);
|
||||
const int nr = recvfrom(this->sock,this->buf,sizeof(this->buf),0,(struct sockaddr *)&from,&fromLen);
|
||||
if (nr > 0) {
|
||||
ZT_Node_processWirePacket(this->node,nullptr,OSUtils::now(),(int64_t)this->sock,&from,this->buf,(unsigned int)nr,this->deadlinePtr);
|
||||
} else {
|
||||
close(this->sock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete this; // closing the socket causes this to exit and delete itself
|
||||
}
|
||||
|
||||
ZT_Node *const node;
|
||||
volatile int64_t *const deadlinePtr;
|
||||
const int sock;
|
||||
Thread thread;
|
||||
char buf[10000];
|
||||
};
|
||||
|
||||
std::vector<int> _sockets;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif // !__WINDOWS__
|
||||
|
||||
#endif
|
@ -1,7 +0,0 @@
|
||||
World Definitions and Generator Code
|
||||
======
|
||||
|
||||
This little bit of code is used to generate world updates. Ordinary users probably will never need this unless they want to test or experiment.
|
||||
|
||||
See mkworld.cpp for documentation. To build from this directory use 'source ./build.sh'.
|
||||
|
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
c++ -std=c++11 -I../.. -I.. -O -o mkworld ../../node/C25519.cpp ../../node/Salsa20.cpp ../../node/SHA512.cpp ../../node/Identity.cpp ../../node/Utils.cpp ../../node/InetAddress.cpp ../../osdep/OSUtils.cpp mkworld.cpp -lm
|
@ -1,154 +0,0 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This utility makes the World from the configuration specified below.
|
||||
* It probably won't be much use to anyone outside ZeroTier, Inc. except
|
||||
* for testing and experimentation purposes.
|
||||
*
|
||||
* If you want to make your own World you must edit this file.
|
||||
*
|
||||
* When run, it expects two files in the current directory:
|
||||
*
|
||||
* previous.c25519 - key pair to sign this world (key from previous world)
|
||||
* current.c25519 - key pair whose public key should be embedded in this world
|
||||
*
|
||||
* If these files do not exist, they are both created with the same key pair
|
||||
* and a self-signed initial World is born.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <node/Constants.hpp>
|
||||
#include <node/World.hpp>
|
||||
#include <node/C25519.hpp>
|
||||
#include <node/Identity.hpp>
|
||||
#include <node/InetAddress.hpp>
|
||||
#include <osdep/OSUtils.hpp>
|
||||
|
||||
using namespace ZeroTier;
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
std::string previous,current;
|
||||
if ((!OSUtils::readFile("previous.c25519",previous))||(!OSUtils::readFile("current.c25519",current))) {
|
||||
C25519::Pair np(C25519::generate());
|
||||
previous = std::string();
|
||||
previous.append((const char *)np.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
previous.append((const char *)np.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
current = previous;
|
||||
OSUtils::writeFile("previous.c25519",previous);
|
||||
OSUtils::writeFile("current.c25519",current);
|
||||
fprintf(stderr,"INFO: created initial world keys: previous.c25519 and current.c25519 (both initially the same)" ZT_EOL_S);
|
||||
}
|
||||
|
||||
if ((previous.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))||(current.length() != (ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_PRIVATE_KEY_LEN))) {
|
||||
fprintf(stderr,"FATAL: previous.c25519 or current.c25519 empty or invalid" ZT_EOL_S);
|
||||
return 1;
|
||||
}
|
||||
C25519::Pair previousKP;
|
||||
memcpy(previousKP.pub.data,previous.data(),ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(previousKP.priv.data,previous.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
C25519::Pair currentKP;
|
||||
memcpy(currentKP.pub.data,current.data(),ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(currentKP.priv.data,current.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
|
||||
// =========================================================================
|
||||
// EDIT BELOW HERE
|
||||
|
||||
std::vector<World::Root> roots;
|
||||
|
||||
const uint64_t id = ZT_WORLD_ID_EARTH;
|
||||
const uint64_t ts = 1562631342273ULL; // July 8th, 2019
|
||||
|
||||
roots.push_back(World::Root());
|
||||
roots.back().identity = Identity("3a46f1bf30:0:76e66fab33e28549a62ee2064d1843273c2c300ba45c3f20bef02dbad225723bb59a9bb4b13535730961aeecf5a163ace477cceb0727025b99ac14a5166a09a3");
|
||||
roots.back().stableEndpoints.push_back(InetAddress("185.180.13.82/9993"));
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2a02:6ea0:c815::/9993"));
|
||||
|
||||
// Alice
|
||||
roots.push_back(World::Root());
|
||||
roots.back().identity = Identity("9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e");
|
||||
roots.back().stableEndpoints.push_back(InetAddress("188.166.94.177/9993")); // Amsterdam
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2a03:b0c0:2:d0::7d:1/9993")); // Amsterdam
|
||||
roots.back().stableEndpoints.push_back(InetAddress("154.66.197.33/9993")); // Johannesburg
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2c0f:f850:154:197::33/9993")); // Johannesburg
|
||||
roots.back().stableEndpoints.push_back(InetAddress("159.203.97.171/9993")); // New York
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2604:a880:800:a1::54:6001/9993")); // New York
|
||||
roots.back().stableEndpoints.push_back(InetAddress("131.255.6.16/9993")); // Buenos Aires
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2803:eb80:0:e::2/9993")); // Buenos Aires
|
||||
roots.back().stableEndpoints.push_back(InetAddress("107.170.197.14/9993")); // San Francisco
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2604:a880:1:20::200:e001/9993")); // San Francisco
|
||||
roots.back().stableEndpoints.push_back(InetAddress("128.199.197.217/9993")); // Singapore
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2400:6180:0:d0::b7:4001/9993")); // Singapore
|
||||
|
||||
// Bob
|
||||
roots.push_back(World::Root());
|
||||
roots.back().identity = Identity("8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c");
|
||||
roots.back().stableEndpoints.push_back(InetAddress("45.32.198.130/9993")); // Dallas
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:6400:81c3:5400:00ff:fe18:1d61/9993")); // Dallas
|
||||
roots.back().stableEndpoints.push_back(InetAddress("46.101.160.249/9993")); // Frankfurt
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2a03:b0c0:3:d0::6a:3001/9993")); // Frankfurt
|
||||
roots.back().stableEndpoints.push_back(InetAddress("107.191.46.210/9993")); // Paris
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:6800:83a4::64/9993")); // Paris
|
||||
roots.back().stableEndpoints.push_back(InetAddress("45.32.246.179/9993")); // Sydney
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:5800:8bf8:5400:ff:fe15:b39a/9993")); // Sydney
|
||||
roots.back().stableEndpoints.push_back(InetAddress("45.32.248.87/9993")); // Tokyo
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2001:19f0:7000:9bc9:5400:00ff:fe15:c4f5/9993")); // Tokyo
|
||||
roots.back().stableEndpoints.push_back(InetAddress("159.203.2.154/9993")); // Toronto
|
||||
roots.back().stableEndpoints.push_back(InetAddress("2604:a880:cad:d0::26:7001/9993")); // Toronto
|
||||
|
||||
// END WORLD DEFINITION
|
||||
// =========================================================================
|
||||
|
||||
fprintf(stderr,"INFO: generating and signing id==%llu ts==%llu" ZT_EOL_S,(unsigned long long)id,(unsigned long long)ts);
|
||||
|
||||
World nw = World::make(World::TYPE_PLANET,id,ts,currentKP.pub,roots,previousKP);
|
||||
|
||||
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> outtmp;
|
||||
nw.serialize(outtmp,false);
|
||||
World testw;
|
||||
testw.deserialize(outtmp,0);
|
||||
if (testw != nw) {
|
||||
fprintf(stderr,"FATAL: serialization test failed!" ZT_EOL_S);
|
||||
return 1;
|
||||
}
|
||||
|
||||
OSUtils::writeFile("world.bin",std::string((const char *)outtmp.data(),outtmp.size()));
|
||||
fprintf(stderr,"INFO: world.bin written with %u bytes of binary world data." ZT_EOL_S,outtmp.size());
|
||||
|
||||
fprintf(stdout,ZT_EOL_S);
|
||||
fprintf(stdout,"#define ZT_DEFAULT_WORLD_LENGTH %u" ZT_EOL_S,outtmp.size());
|
||||
fprintf(stdout,"static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {");
|
||||
for(unsigned int i=0;i<outtmp.size();++i) {
|
||||
const unsigned char *d = (const unsigned char *)outtmp.data();
|
||||
if (i > 0)
|
||||
fprintf(stdout,",");
|
||||
fprintf(stdout,"0x%.2x",(unsigned int)d[i]);
|
||||
}
|
||||
fprintf(stdout,"};" ZT_EOL_S);
|
||||
|
||||
return 0;
|
||||
}
|
Binary file not shown.
@ -1,3 +0,0 @@
|
||||
|
||||
#define ZT_DEFAULT_WORLD_LENGTH 732
|
||||
static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x6b,0xd4,0x16,0x08,0xc1,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x16,0x93,0xf4,0xe5,0xbd,0x20,0xda,0x10,0xad,0xc7,0x05,0xf4,0x99,0xfe,0x04,0x08,0x9b,0xe0,0x9e,0x77,0x1d,0x9f,0x47,0x16,0xaa,0x92,0x4f,0x10,0x16,0x3d,0xc7,0xec,0xd3,0x90,0x9e,0xd1,0x74,0xfc,0xb3,0xb5,0x07,0x9c,0x4d,0x95,0xc5,0x17,0x8b,0x3d,0x0b,0x60,0x76,0xe8,0x51,0xbb,0xb6,0x3d,0x74,0xb5,0x21,0x83,0x7b,0x95,0x1d,0x02,0x9b,0xcd,0xaf,0x5c,0x3e,0x96,0xdf,0x37,0x2c,0x56,0x6d,0xfa,0x75,0x0f,0xda,0x55,0x85,0x13,0xf4,0x76,0x1a,0x66,0x4d,0x3b,0x8d,0xcf,0x12,0xc9,0x34,0xb9,0x0d,0x61,0x03,0x3a,0x46,0xf1,0xbf,0x30,0x00,0x76,0xe6,0x6f,0xab,0x33,0xe2,0x85,0x49,0xa6,0x2e,0xe2,0x06,0x4d,0x18,0x43,0x27,0x3c,0x2c,0x30,0x0b,0xa4,0x5c,0x3f,0x20,0xbe,0xf0,0x2d,0xba,0xd2,0x25,0x72,0x3b,0xb5,0x9a,0x9b,0xb4,0xb1,0x35,0x35,0x73,0x09,0x61,0xae,0xec,0xf5,0xa1,0x63,0xac,0xe4,0x77,0xcc,0xeb,0x07,0x27,0x02,0x5b,0x99,0xac,0x14,0xa5,0x16,0x6a,0x09,0xa3,0x00,0x02,0x04,0xb9,0xb4,0x0d,0x52,0x27,0x09,0x06,0x2a,0x02,0x6e,0xa0,0xc8,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x09,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0x83,0xff,0x06,0x10,0x27,0x09,0x06,0x28,0x03,0xeb,0x80,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09};
|
@ -1393,24 +1393,6 @@ enum ZT_StateObjectType
|
||||
*/
|
||||
ZT_STATE_OBJECT_IDENTITY_SECRET = 2,
|
||||
|
||||
/**
|
||||
* The planet (there is only one per... well... planet!)
|
||||
*
|
||||
* Object ID: world ID of planet, or 0 if unknown (first query)
|
||||
* Canonical path: <HOME>/planet
|
||||
* Persistence: recommended
|
||||
*/
|
||||
ZT_STATE_OBJECT_PLANET = 3,
|
||||
|
||||
/**
|
||||
* A moon (federated root set)
|
||||
*
|
||||
* Object ID: world ID of moon
|
||||
* Canonical path: <HOME>/moons.d/<ID>.moon (16-digit hex ID)
|
||||
* Persistence: required if moon memberships should persist
|
||||
*/
|
||||
ZT_STATE_OBJECT_MOON = 4,
|
||||
|
||||
/**
|
||||
* Peer and related state
|
||||
*
|
||||
@ -1847,32 +1829,6 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tpt
|
||||
*/
|
||||
ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
|
||||
|
||||
/**
|
||||
* Add or update a moon
|
||||
*
|
||||
* Moons are persisted in the data store in moons.d/, so this can persist
|
||||
* across invocations if the contents of moon.d are scanned and orbit is
|
||||
* called for each on startup.
|
||||
*
|
||||
* @param node Node instance
|
||||
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
|
||||
* @param moonWorldId Moon's world ID
|
||||
* @param moonSeed If non-zero, the ZeroTier address of any member of the moon to query for moon definition
|
||||
* @param len Length of moonWorld in bytes
|
||||
* @return Error if moon was invalid or failed to be added
|
||||
*/
|
||||
ZT_SDK_API enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed);
|
||||
|
||||
/**
|
||||
* Remove a moon (does nothing if not present)
|
||||
*
|
||||
* @param node Node instance
|
||||
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
|
||||
* @param moonWorldId World ID of moon to remove
|
||||
* @return Error if anything bad happened
|
||||
*/
|
||||
ZT_SDK_API enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId);
|
||||
|
||||
/**
|
||||
* Get this node's 40-bit ZeroTier address
|
||||
*
|
||||
|
@ -98,7 +98,6 @@ public:
|
||||
* @param keylen Number of key bytes to generate
|
||||
*/
|
||||
static void agree(const Private &mine,const Public &their,void *keybuf,unsigned int keylen);
|
||||
static inline void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen) { agree(mine.priv,their,keybuf,keylen); }
|
||||
|
||||
/**
|
||||
* Sign a message with a sender's key pair
|
||||
@ -120,7 +119,6 @@ public:
|
||||
* @param signature Buffer to fill with signature -- MUST be 96 bytes in length
|
||||
*/
|
||||
static void sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len,void *signature);
|
||||
static inline void sign(const Pair &mine,const void *msg,unsigned int len,void *signature) { sign(mine.priv,mine.pub,msg,len,signature); }
|
||||
|
||||
/**
|
||||
* Sign a message with a sender's key pair
|
||||
|
@ -34,6 +34,23 @@
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
bool Capability::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].signatureLength = from.sign(tmp.data(),tmp.size(),_custody[i].signature,sizeof(_custody[i].signature));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const
|
||||
{
|
||||
try {
|
||||
@ -57,7 +74,7 @@ int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const
|
||||
|
||||
const Identity id(RR->topology->getIdentity(tPtr,_custody[c].from));
|
||||
if (id) {
|
||||
if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature))
|
||||
if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature,_custody[c].signatureLength))
|
||||
return -1;
|
||||
} else {
|
||||
RR->sw->requestWhois(tPtr,RR->node->now(),_custody[c].from);
|
||||
|
@ -154,22 +154,7 @@ public:
|
||||
* @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;
|
||||
}
|
||||
bool sign(const Identity &from,const Address &to);
|
||||
|
||||
/**
|
||||
* Verify this capability's chain of custody and signatures
|
||||
@ -409,9 +394,9 @@ public:
|
||||
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);
|
||||
b.append((uint8_t)1);
|
||||
b.append((uint16_t)_custody[i].signatureLength);
|
||||
b.append(_custody[i].signature,_custody[i].signatureLength);
|
||||
} else {
|
||||
b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain
|
||||
break;
|
||||
@ -454,10 +439,11 @@ public:
|
||||
_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)
|
||||
_custody[i].signatureLength = b.template at<uint16_t>(p);
|
||||
if (_custody[i].signatureLength > sizeof(_custody[i].signature))
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
|
||||
p += 2;
|
||||
memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
|
||||
memcpy(_custody[i].signature,b.field(p,_custody[i].signatureLength),_custody[i].signatureLength); p += _custody[i].signatureLength;
|
||||
} else {
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
}
|
||||
@ -489,7 +475,8 @@ private:
|
||||
struct {
|
||||
Address to;
|
||||
Address from;
|
||||
C25519::Signature signature;
|
||||
unsigned int signatureLength;
|
||||
uint8_t signature[ZT_SIGNATURE_BUFFER_SIZE];
|
||||
} _custody[ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH];
|
||||
};
|
||||
|
||||
|
@ -84,7 +84,7 @@ std::string CertificateOfMembership::toString() const
|
||||
|
||||
if (_signedBy) {
|
||||
s.push_back(':');
|
||||
s.append(Utils::hex(_signature.data,ZT_C25519_SIGNATURE_LEN,tmp));
|
||||
s.append(Utils::hex(_signature,_signatureLength,tmp));
|
||||
}
|
||||
|
||||
return s;
|
||||
@ -92,9 +92,9 @@ std::string CertificateOfMembership::toString() const
|
||||
|
||||
void CertificateOfMembership::fromString(const char *s)
|
||||
{
|
||||
_qualifierCount = 0;
|
||||
_signedBy.zero();
|
||||
memset(_signature.data,0,ZT_C25519_SIGNATURE_LEN);
|
||||
_qualifierCount = 0;
|
||||
_signatureLength = 0;
|
||||
|
||||
if (!*s)
|
||||
return;
|
||||
@ -145,8 +145,7 @@ void CertificateOfMembership::fromString(const char *s)
|
||||
colonAt = 0;
|
||||
while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
|
||||
if (colonAt) {
|
||||
if (Utils::unhex(s,colonAt,_signature.data,ZT_C25519_SIGNATURE_LEN) != ZT_C25519_SIGNATURE_LEN)
|
||||
_signedBy.zero();
|
||||
_signatureLength = Utils::unhex(s,colonAt,_signature,sizeof(_signature));
|
||||
} else {
|
||||
_signedBy.zero();
|
||||
}
|
||||
@ -208,7 +207,7 @@ bool CertificateOfMembership::sign(const Identity &with)
|
||||
}
|
||||
|
||||
try {
|
||||
_signature = with.sign(buf,ptr * sizeof(uint64_t));
|
||||
_signatureLength = with.sign(buf,ptr * sizeof(uint64_t),_signature,sizeof(_signature));
|
||||
_signedBy = with.address();
|
||||
return true;
|
||||
} catch ( ... ) {
|
||||
@ -235,7 +234,7 @@ int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) con
|
||||
buf[ptr++] = Utils::hton(_qualifiers[i].value);
|
||||
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
|
||||
}
|
||||
return (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1);
|
||||
return (id.verify(buf,ptr * sizeof(uint64_t),_signature,_signatureLength) ? 0 : -1);
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -113,7 +113,8 @@ public:
|
||||
* Create an empty certificate of membership
|
||||
*/
|
||||
CertificateOfMembership() :
|
||||
_qualifierCount(0) {}
|
||||
_qualifierCount(0),
|
||||
_signatureLength(0) {}
|
||||
|
||||
/**
|
||||
* Create from required fields common to all networks
|
||||
@ -135,7 +136,7 @@ public:
|
||||
_qualifiers[2].value = issuedTo.toInt();
|
||||
_qualifiers[2].maxDelta = 0xffffffffffffffffULL;
|
||||
_qualifierCount = 3;
|
||||
memset(_signature.data,0,ZT_C25519_SIGNATURE_LEN);
|
||||
_signatureLength = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -279,8 +280,13 @@ public:
|
||||
b.append(_qualifiers[i].maxDelta);
|
||||
}
|
||||
_signedBy.appendTo(b);
|
||||
if (_signedBy)
|
||||
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
|
||||
if ((_signedBy)&&(_signatureLength == 96)) {
|
||||
// UGLY: Ed25519 signatures in ZT are 96 bytes (64 + 32 bytes of hash).
|
||||
// P-384 signatures are also 96 bytes, praise the horned one. That means
|
||||
// we don't need to include a length. If we ever do we will need a new
|
||||
// serialized object version, but only for those with length != 96.
|
||||
b.append(_signature,96);
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
@ -288,8 +294,9 @@ public:
|
||||
{
|
||||
unsigned int p = startAt;
|
||||
|
||||
_qualifierCount = 0;
|
||||
_signedBy.zero();
|
||||
_qualifierCount = 0;
|
||||
_signatureLength = 0;
|
||||
|
||||
if (b[p++] != 1)
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
|
||||
@ -316,8 +323,10 @@ public:
|
||||
p += ZT_ADDRESS_LENGTH;
|
||||
|
||||
if (_signedBy) {
|
||||
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
|
||||
p += ZT_C25519_SIGNATURE_LEN;
|
||||
// See "UGLY" comment in serialize()...
|
||||
_signatureLength = 96;
|
||||
memcpy(_signature,b.field(p,96),96);
|
||||
p += 96;
|
||||
}
|
||||
|
||||
return (p - startAt);
|
||||
@ -329,13 +338,15 @@ public:
|
||||
return false;
|
||||
if (_qualifierCount != c._qualifierCount)
|
||||
return false;
|
||||
if (_signatureLength != c._signatureLength)
|
||||
return false;
|
||||
for(unsigned int i=0;i<_qualifierCount;++i) {
|
||||
const _Qualifier &a = _qualifiers[i];
|
||||
const _Qualifier &b = c._qualifiers[i];
|
||||
if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta))
|
||||
return false;
|
||||
}
|
||||
return (memcmp(_signature.data,c._signature.data,ZT_C25519_SIGNATURE_LEN) == 0);
|
||||
return (memcmp(_signature,c._signature,_signatureLength) == 0);
|
||||
}
|
||||
inline bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
|
||||
|
||||
@ -352,7 +363,8 @@ private:
|
||||
Address _signedBy;
|
||||
_Qualifier _qualifiers[ZT_NETWORK_COM_MAX_QUALIFIERS];
|
||||
unsigned int _qualifierCount;
|
||||
C25519::Signature _signature;
|
||||
unsigned int _signatureLength;
|
||||
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -34,6 +34,32 @@
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
void CertificateOfOwnership::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;
|
||||
}
|
||||
}
|
||||
|
||||
bool CertificateOfOwnership::sign(const Identity &signer)
|
||||
{
|
||||
if (signer.hasPrivate()) {
|
||||
Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
|
||||
_signedBy = signer.address();
|
||||
this->serialize(tmp,true);
|
||||
_signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) const
|
||||
{
|
||||
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
|
||||
@ -46,7 +72,7 @@ int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) cons
|
||||
try {
|
||||
Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp;
|
||||
this->serialize(tmp,true);
|
||||
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
|
||||
return (id.verify(tmp.data(),tmp.size(),_signature,_signatureLength) ? 0 : -1);
|
||||
} catch ( ... ) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -107,19 +107,7 @@ public:
|
||||
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;
|
||||
}
|
||||
}
|
||||
void addThing(const InetAddress &ip);
|
||||
|
||||
inline void addThing(const MAC &mac)
|
||||
{
|
||||
@ -133,17 +121,7 @@ public:
|
||||
* @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;
|
||||
}
|
||||
bool sign(const Identity &signer);
|
||||
|
||||
/**
|
||||
* @param RR Runtime environment to allow identity lookup for signedBy
|
||||
@ -170,9 +148,9 @@ public:
|
||||
_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((uint8_t)1);
|
||||
b.append((uint16_t)_signatureLength); // length of signature
|
||||
b.append(_signature,_signatureLength);
|
||||
}
|
||||
|
||||
b.append((uint16_t)0); // length of additional fields, currently 0
|
||||
@ -203,10 +181,11 @@ public:
|
||||
_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)
|
||||
_signatureLength = b.template at<uint16_t>(p);
|
||||
if (_signatureLength > sizeof(_signature))
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
|
||||
p += 2;
|
||||
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
|
||||
memcpy(_signature,b.field(p,_signatureLength),_signatureLength); p += _signatureLength;
|
||||
} else {
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
}
|
||||
@ -236,7 +215,8 @@ private:
|
||||
uint8_t _thingValues[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS][ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE];
|
||||
Address _issuedTo;
|
||||
Address _signedBy;
|
||||
C25519::Signature _signature;
|
||||
unsigned int _signatureLength;
|
||||
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -613,6 +613,11 @@
|
||||
*/
|
||||
#define ZT_SUPPORT_OLD_STYLE_NETCONF 1
|
||||
|
||||
/**
|
||||
* Size of a buffer to store either a C25519 or an ECC P-384 signature
|
||||
*/
|
||||
#define ZT_SIGNATURE_BUFFER_SIZE 96
|
||||
|
||||
/**
|
||||
* Desired buffer size for UDP sockets (used in service and osdep but defined here)
|
||||
*/
|
||||
|
@ -61,12 +61,46 @@
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Generate a NIST P-384 key pair
|
||||
*
|
||||
* @param pub Buffer to receive point compressed public key
|
||||
* @param priv Buffer to receiver private key
|
||||
*/
|
||||
void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE]);
|
||||
|
||||
/**
|
||||
* Sign a hash with a NIST P-384 private key
|
||||
*
|
||||
* The hash must be 48 bytes in size and is typically the first 48 bytes
|
||||
* of a SHA512 hash or something similar. Extra bytes of course are ignored.
|
||||
*
|
||||
* @param priv Private key
|
||||
* @param hash 48-byte hash
|
||||
* @param sig Buffer to receive signature
|
||||
*/
|
||||
void ECC384ECDSASign(const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE],const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]);
|
||||
|
||||
/**
|
||||
* Verify a signature
|
||||
*
|
||||
* @param pub Public key
|
||||
* @param hash 48-byte hash (usually first 48 bytes of SHA512(msg))
|
||||
* @param sig Signature to check
|
||||
* @return True if signature is valid
|
||||
*/
|
||||
bool ECC384ECDSAVerify(const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],const uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]);
|
||||
|
||||
/**
|
||||
* Perform ECDH key agreement
|
||||
*
|
||||
* The secret generated here is the raw 48-byte result of ECDH.
|
||||
* It's typically hashed prior to use.
|
||||
*
|
||||
* @param theirPub Remote public key
|
||||
* @param ourPriv Local private key
|
||||
* @param secret Buffer to receive 48-byte secret
|
||||
*/
|
||||
bool ECC384ECDH(const uint8_t theirPub[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_t ourPriv[ZT_ECC384_PRIVATE_KEY_SIZE],uint8_t secret[ZT_ECC384_SHARED_SECRET_SIZE]);
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -35,14 +35,16 @@
|
||||
#include "Salsa20.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// This is the memory-hard hash used for type 0 identities' addresses
|
||||
|
||||
// These can't be changed without a new identity type. They define the
|
||||
// parameters of the hashcash hashing/searching algorithm.
|
||||
|
||||
#define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 17
|
||||
#define ZT_IDENTITY_GEN_MEMORY 2097152
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
// A memory-hard composition of SHA-512 and Salsa20 for hashcash hashing
|
||||
static inline void _computeMemoryHardHash(const void *publicKey,unsigned int publicKeyBytes,void *digest,void *genmem)
|
||||
{
|
||||
@ -94,23 +96,39 @@ struct _Identity_generate_cond
|
||||
char *genmem;
|
||||
};
|
||||
|
||||
void Identity::generate()
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Identity::generate(const Type t)
|
||||
{
|
||||
unsigned char digest[64];
|
||||
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
|
||||
uint8_t digest[64];
|
||||
switch(t) {
|
||||
case C25519: {
|
||||
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
|
||||
|
||||
C25519::Pair kp;
|
||||
do {
|
||||
kp = C25519::generateSatisfying(_Identity_generate_cond(digest,genmem));
|
||||
_address.setTo(digest + 59,ZT_ADDRESS_LENGTH); // last 5 bytes are address
|
||||
} while (_address.isReserved());
|
||||
C25519::Pair kp;
|
||||
do {
|
||||
kp = C25519::generateSatisfying(_Identity_generate_cond(digest,genmem));
|
||||
_address.setTo(digest + 59,ZT_ADDRESS_LENGTH); // last 5 bytes are address
|
||||
} while (_address.isReserved());
|
||||
|
||||
_publicKey = kp.pub;
|
||||
if (!_privateKey)
|
||||
_privateKey = new C25519::Private();
|
||||
*_privateKey = kp.priv;
|
||||
memcpy(_k.t0.pub.data,kp.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(_k.t0.priv.data,kp.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
_type = C25519;
|
||||
_hasPrivate = true;
|
||||
|
||||
delete [] genmem;
|
||||
} break;
|
||||
|
||||
delete [] genmem;
|
||||
case P384: {
|
||||
do {
|
||||
ECC384GenerateKey(_k.t1.pub,_k.t1.priv);
|
||||
SHA512::hash(digest,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE);
|
||||
_address.setTo(digest + 59,ZT_ADDRESS_LENGTH);
|
||||
} while (_address.isReserved());
|
||||
_type = P384;
|
||||
_hasPrivate = true;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Identity::locallyValidate() const
|
||||
@ -118,40 +136,70 @@ bool Identity::locallyValidate() const
|
||||
if (_address.isReserved())
|
||||
return false;
|
||||
|
||||
unsigned char digest[64];
|
||||
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
|
||||
_computeMemoryHardHash(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
|
||||
delete [] genmem;
|
||||
switch(_type) {
|
||||
case C25519: {
|
||||
unsigned char digest[64];
|
||||
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
|
||||
_computeMemoryHardHash(_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
|
||||
delete [] genmem;
|
||||
unsigned char addrb[5];
|
||||
_address.copyTo(addrb,5);
|
||||
return (
|
||||
(digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN)&&
|
||||
(digest[59] == addrb[0])&&
|
||||
(digest[60] == addrb[1])&&
|
||||
(digest[61] == addrb[2])&&
|
||||
(digest[62] == addrb[3])&&
|
||||
(digest[63] == addrb[4]));
|
||||
} break;
|
||||
|
||||
unsigned char addrb[5];
|
||||
_address.copyTo(addrb,5);
|
||||
case P384: {
|
||||
return true;
|
||||
} break;
|
||||
}
|
||||
|
||||
return (
|
||||
(digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN)&&
|
||||
(digest[59] == addrb[0])&&
|
||||
(digest[60] == addrb[1])&&
|
||||
(digest[61] == addrb[2])&&
|
||||
(digest[62] == addrb[3])&&
|
||||
(digest[63] == addrb[4]));
|
||||
return false;
|
||||
}
|
||||
|
||||
char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
|
||||
{
|
||||
char *p = buf;
|
||||
Utils::hex10(_address.toInt(),p);
|
||||
p += 10;
|
||||
*(p++) = ':';
|
||||
*(p++) = '0';
|
||||
*(p++) = ':';
|
||||
Utils::hex(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN,p);
|
||||
p += ZT_C25519_PUBLIC_KEY_LEN * 2;
|
||||
if ((_privateKey)&&(includePrivate)) {
|
||||
*(p++) = ':';
|
||||
Utils::hex(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN,p);
|
||||
p += ZT_C25519_PRIVATE_KEY_LEN * 2;
|
||||
switch(_type) {
|
||||
case C25519: {
|
||||
char *p = buf;
|
||||
Utils::hex10(_address.toInt(),p);
|
||||
p += 10;
|
||||
*(p++) = ':';
|
||||
*(p++) = '0';
|
||||
*(p++) = ':';
|
||||
Utils::hex(_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN,p);
|
||||
p += ZT_C25519_PUBLIC_KEY_LEN * 2;
|
||||
if ((_hasPrivate)&&(includePrivate)) {
|
||||
*(p++) = ':';
|
||||
Utils::hex(_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN,p);
|
||||
p += ZT_C25519_PRIVATE_KEY_LEN * 2;
|
||||
}
|
||||
*p = (char)0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
case P384: {
|
||||
char *p = buf;
|
||||
Utils::hex10(_address.toInt(),p);
|
||||
p += 10;
|
||||
*(p++) = ':';
|
||||
*(p++) = '1';
|
||||
*(p++) = ':';
|
||||
Utils::hex(_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE,p);
|
||||
p += ZT_ECC384_PUBLIC_KEY_SIZE * 2;
|
||||
if ((_hasPrivate)&&(includePrivate)) {
|
||||
*(p++) = ':';
|
||||
Utils::hex(_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE,p);
|
||||
p += ZT_ECC384_PRIVATE_KEY_SIZE * 2;
|
||||
}
|
||||
*p = (char)0;
|
||||
return buf;
|
||||
} break;
|
||||
}
|
||||
*p = (char)0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool Identity::fromString(const char *str)
|
||||
@ -166,8 +214,7 @@ bool Identity::fromString(const char *str)
|
||||
return false;
|
||||
}
|
||||
|
||||
delete _privateKey;
|
||||
_privateKey = (C25519::Private *)0;
|
||||
_hasPrivate = false;
|
||||
|
||||
int fno = 0;
|
||||
char *saveptr = (char *)0;
|
||||
@ -181,22 +228,49 @@ bool Identity::fromString(const char *str)
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if ((f[0] != '0')||(f[1])) {
|
||||
if ((f[0] == '0')&&(!f[1])) {
|
||||
_type = C25519;
|
||||
} else if ((f[0] == '1')&&(!f[1])) {
|
||||
_type = P384;
|
||||
} else {
|
||||
_address.zero();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (Utils::unhex(f,_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
|
||||
_address.zero();
|
||||
return false;
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
if (Utils::unhex(f,_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
|
||||
_address.zero();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case P384:
|
||||
if (Utils::unhex(f,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE) != ZT_ECC384_PUBLIC_KEY_SIZE) {
|
||||
_address.zero();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
_privateKey = new C25519::Private();
|
||||
if (Utils::unhex(f,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
|
||||
_address.zero();
|
||||
return false;
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
if (Utils::unhex(f,_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
|
||||
_address.zero();
|
||||
return false;
|
||||
} else {
|
||||
_hasPrivate = true;
|
||||
}
|
||||
break;
|
||||
case P384:
|
||||
if (Utils::unhex(f,_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE) != ZT_ECC384_PRIVATE_KEY_SIZE) {
|
||||
_address.zero();
|
||||
return false;
|
||||
} else {
|
||||
_hasPrivate = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "C25519.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "SHA512.hpp"
|
||||
#include "ECC384.hpp"
|
||||
|
||||
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 384
|
||||
|
||||
@ -54,61 +55,45 @@ namespace ZeroTier {
|
||||
class Identity
|
||||
{
|
||||
public:
|
||||
Identity() :
|
||||
_privateKey((C25519::Private *)0)
|
||||
enum Type
|
||||
{
|
||||
}
|
||||
C25519 = 0, // Curve25519 and Ed25519
|
||||
P384 = 1 // NIST P-384 ECDH and ECDSA
|
||||
};
|
||||
|
||||
Identity(const Identity &id) :
|
||||
_address(id._address),
|
||||
_publicKey(id._publicKey),
|
||||
_privateKey((id._privateKey) ? new C25519::Private(*(id._privateKey)) : (C25519::Private *)0)
|
||||
{
|
||||
}
|
||||
Identity() { memset(reinterpret_cast<void *>(this),0,sizeof(Identity)); }
|
||||
Identity(const Identity &id) { memcpy(reinterpret_cast<void *>(this),&id,sizeof(Identity)); }
|
||||
|
||||
Identity(const char *str) :
|
||||
_privateKey((C25519::Private *)0)
|
||||
Identity(const char *str)
|
||||
{
|
||||
if (!fromString(str))
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
Identity(const Buffer<C> &b,unsigned int startAt = 0) :
|
||||
_privateKey((C25519::Private *)0)
|
||||
{
|
||||
deserialize(b,startAt);
|
||||
}
|
||||
Identity(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); }
|
||||
|
||||
~Identity()
|
||||
{
|
||||
if (_privateKey) {
|
||||
Utils::burn(_privateKey,sizeof(C25519::Private));
|
||||
delete _privateKey;
|
||||
}
|
||||
}
|
||||
~Identity() { Utils::burn(reinterpret_cast<void *>(this),sizeof(Identity)); }
|
||||
|
||||
inline Identity &operator=(const Identity &id)
|
||||
{
|
||||
_address = id._address;
|
||||
_publicKey = id._publicKey;
|
||||
if (id._privateKey) {
|
||||
if (!_privateKey)
|
||||
_privateKey = new C25519::Private();
|
||||
*_privateKey = *(id._privateKey);
|
||||
} else {
|
||||
delete _privateKey;
|
||||
_privateKey = (C25519::Private *)0;
|
||||
}
|
||||
memcpy(reinterpret_cast<void *>(this),&id,sizeof(Identity));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Identity type
|
||||
*/
|
||||
inline Type type() const { return _type; }
|
||||
|
||||
/**
|
||||
* Generate a new identity (address, key pair)
|
||||
*
|
||||
* This is a time consuming operation.
|
||||
*
|
||||
* @param t Type of identity to generate
|
||||
*/
|
||||
void generate();
|
||||
void generate(const Type t);
|
||||
|
||||
/**
|
||||
* Check the validity of this identity's pairing of key to address
|
||||
@ -120,7 +105,7 @@ public:
|
||||
/**
|
||||
* @return True if this identity contains a private key
|
||||
*/
|
||||
inline bool hasPrivate() const { return (_privateKey != (C25519::Private *)0); }
|
||||
inline bool hasPrivate() const { return _hasPrivate; }
|
||||
|
||||
/**
|
||||
* Compute the SHA512 hash of our private key (if we have one)
|
||||
@ -130,9 +115,15 @@ public:
|
||||
*/
|
||||
inline bool sha512PrivateKey(void *sha) const
|
||||
{
|
||||
if (_privateKey) {
|
||||
SHA512::hash(sha,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
return true;
|
||||
if (_hasPrivate) {
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
SHA512::hash(sha,_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
return true;
|
||||
case P384:
|
||||
SHA512::hash(sha,_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -140,14 +131,34 @@ public:
|
||||
/**
|
||||
* Sign a message with this identity (private key required)
|
||||
*
|
||||
* The signature buffer should be large enough for the largest
|
||||
* signature, which is currently 96 bytes.
|
||||
*
|
||||
* @param data Data to sign
|
||||
* @param len Length of data
|
||||
* @param sig Buffer to receive signature
|
||||
* @param siglen Length of buffer
|
||||
* @return Number of bytes actually written to sig or 0 on error
|
||||
*/
|
||||
inline C25519::Signature sign(const void *data,unsigned int len) const
|
||||
inline unsigned int sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
|
||||
{
|
||||
if (_privateKey)
|
||||
return C25519::sign(*_privateKey,_publicKey,data,len);
|
||||
throw ZT_EXCEPTION_PRIVATE_KEY_REQUIRED;
|
||||
uint8_t h[64];
|
||||
if (!_hasPrivate)
|
||||
return 0;
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
if (siglen < ZT_C25519_SIGNATURE_LEN)
|
||||
return 0;
|
||||
C25519::sign(_k.t0.priv,_k.t0.pub,data,len,sig);
|
||||
return ZT_C25519_SIGNATURE_LEN;
|
||||
case P384:
|
||||
if (siglen < ZT_ECC384_SIGNATURE_SIZE)
|
||||
return 0;
|
||||
SHA512::hash(h,data,len);
|
||||
ECC384ECDSASign(_k.t1.priv,h,(uint8_t *)sig);
|
||||
return ZT_ECC384_SIGNATURE_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,17 +170,20 @@ public:
|
||||
* @param siglen Length of signature in bytes
|
||||
* @return True if signature validates and data integrity checks
|
||||
*/
|
||||
inline bool verify(const void *data,unsigned int len,const void *signature,unsigned int siglen) const { return C25519::verify(_publicKey,data,len,signature,siglen); }
|
||||
|
||||
/**
|
||||
* Verify a message signature against this identity
|
||||
*
|
||||
* @param data Data to check
|
||||
* @param len Length of data
|
||||
* @param signature Signature
|
||||
* @return True if signature validates and data integrity checks
|
||||
*/
|
||||
inline bool verify(const void *data,unsigned int len,const C25519::Signature &signature) const { return C25519::verify(_publicKey,data,len,signature); }
|
||||
inline bool verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const
|
||||
{
|
||||
uint8_t h[64];
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
return C25519::verify(_k.t0.pub,data,len,sig,siglen);
|
||||
case P384:
|
||||
if (siglen != ZT_ECC384_SIGNATURE_SIZE)
|
||||
return false;
|
||||
SHA512::hash(h,data,len);
|
||||
return ECC384ECDSAVerify(_k.t1.pub,h,(const uint8_t *)sig);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut method to perform key agreement with another identity
|
||||
@ -183,9 +197,26 @@ public:
|
||||
*/
|
||||
inline bool agree(const Identity &id,void *key,unsigned int klen) const
|
||||
{
|
||||
if (_privateKey) {
|
||||
C25519::agree(*_privateKey,id._publicKey,key,klen);
|
||||
return true;
|
||||
uint8_t ecc384RawSecret[ZT_ECC384_SHARED_SECRET_SIZE];
|
||||
uint8_t h[64];
|
||||
if (_hasPrivate) {
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
C25519::agree(_k.t0.priv,id._k.t0.pub,key,klen);
|
||||
return true;
|
||||
case P384:
|
||||
ECC384ECDH(id._k.t1.pub,_k.t1.priv,ecc384RawSecret);
|
||||
SHA512::hash(h,ecc384RawSecret,sizeof(ecc384RawSecret));
|
||||
unsigned int hi = 0;
|
||||
for(unsigned int i=0;i<klen;++i) {
|
||||
if (hi == 64) {
|
||||
hi = 0;
|
||||
SHA512::hash(h,h,64);
|
||||
}
|
||||
((uint8_t *)key)[i] = h[hi++];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -206,12 +237,28 @@ public:
|
||||
inline void serialize(Buffer<C> &b,bool includePrivate = false) const
|
||||
{
|
||||
_address.appendTo(b);
|
||||
b.append((uint8_t)0); // C25519/Ed25519 identity type
|
||||
b.append(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
if ((_privateKey)&&(includePrivate)) {
|
||||
b.append((unsigned char)ZT_C25519_PRIVATE_KEY_LEN);
|
||||
b.append(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
} else b.append((unsigned char)0);
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
b.append((uint8_t)C25519);
|
||||
b.append(_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
if ((_hasPrivate)&&(includePrivate)) {
|
||||
b.append((uint8_t)ZT_C25519_PRIVATE_KEY_LEN);
|
||||
b.append(_k.t0.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
} else {
|
||||
b.append((uint8_t)0);
|
||||
}
|
||||
break;
|
||||
case P384:
|
||||
b.append((uint8_t)P384);
|
||||
b.append(_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE);
|
||||
if ((_hasPrivate)&&(includePrivate)) {
|
||||
b.append((uint8_t)ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
b.append(_k.t1.priv,ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
} else {
|
||||
b.append((uint8_t)0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -229,27 +276,47 @@ public:
|
||||
template<unsigned int C>
|
||||
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
|
||||
{
|
||||
delete _privateKey;
|
||||
_privateKey = (C25519::Private *)0;
|
||||
|
||||
_hasPrivate = false;
|
||||
unsigned int p = startAt;
|
||||
unsigned int pkl;
|
||||
|
||||
_address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
|
||||
p += ZT_ADDRESS_LENGTH;
|
||||
|
||||
if (b[p++] != 0)
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
|
||||
|
||||
memcpy(_publicKey.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
|
||||
p += ZT_C25519_PUBLIC_KEY_LEN;
|
||||
|
||||
unsigned int privateKeyLength = (unsigned int)b[p++];
|
||||
if (privateKeyLength) {
|
||||
if (privateKeyLength != ZT_C25519_PRIVATE_KEY_LEN)
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
|
||||
_privateKey = new C25519::Private();
|
||||
memcpy(_privateKey->data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
|
||||
p += ZT_C25519_PRIVATE_KEY_LEN;
|
||||
_type = (Type)b[p++];
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
memcpy(_k.t0.pub.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
|
||||
p += ZT_C25519_PUBLIC_KEY_LEN;
|
||||
pkl = (unsigned int)b[p++];
|
||||
if (pkl) {
|
||||
if (pkl != ZT_C25519_PRIVATE_KEY_LEN)
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
|
||||
_hasPrivate = true;
|
||||
memcpy(_k.t0.priv.data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
|
||||
p += ZT_C25519_PRIVATE_KEY_LEN;
|
||||
} else {
|
||||
memset(_k.t0.priv.data,0,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
_hasPrivate = false;
|
||||
}
|
||||
break;
|
||||
case P384:
|
||||
memcpy(_k.t0.pub.data,b.field(p,ZT_ECC384_PUBLIC_KEY_SIZE),ZT_ECC384_PUBLIC_KEY_SIZE);
|
||||
p += ZT_ECC384_PUBLIC_KEY_SIZE;
|
||||
pkl = (unsigned int)b[p++];
|
||||
if (pkl) {
|
||||
if (pkl != ZT_ECC384_PRIVATE_KEY_SIZE)
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
|
||||
_hasPrivate = true;
|
||||
memcpy(_k.t1.priv,b.field(p,ZT_ECC384_PRIVATE_KEY_SIZE),ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
p += ZT_ECC384_PRIVATE_KEY_SIZE;
|
||||
} else {
|
||||
memset(_k.t1.priv,0,ZT_ECC384_PRIVATE_KEY_SIZE);
|
||||
_hasPrivate = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
|
||||
}
|
||||
|
||||
return (p - startAt);
|
||||
@ -275,40 +342,64 @@ public:
|
||||
*/
|
||||
bool fromString(const char *str);
|
||||
|
||||
/**
|
||||
* @return C25519 public key
|
||||
*/
|
||||
inline const C25519::Public &publicKey() const { return _publicKey; }
|
||||
|
||||
/**
|
||||
* @return C25519 key pair (only returns valid pair if private key is present in this Identity object)
|
||||
*/
|
||||
inline const C25519::Pair privateKeyPair() const
|
||||
{
|
||||
C25519::Pair pair;
|
||||
pair.pub = _publicKey;
|
||||
if (_privateKey)
|
||||
pair.priv = *_privateKey;
|
||||
else memset(pair.priv.data,0,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
return pair;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if this identity contains something
|
||||
*/
|
||||
inline operator bool() const { return (_address); }
|
||||
|
||||
inline bool operator==(const Identity &id) const { return ((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) == 0)); }
|
||||
inline bool operator<(const Identity &id) const { return ((_address < id._address)||((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) < 0))); }
|
||||
inline bool operator==(const Identity &id) const
|
||||
{
|
||||
if ((_address == id._address)&&(_type == id._type)) {
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
return (memcmp(_k.t0.pub.data,id._k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN) == 0);
|
||||
case P384:
|
||||
return (memcmp(_k.t1.pub,id._k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE) == 0);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline bool operator<(const Identity &id) const
|
||||
{
|
||||
if (_address < id._address)
|
||||
return true;
|
||||
if (_address == id._address) {
|
||||
if ((int)_type < (int)id._type)
|
||||
return true;
|
||||
if (_type == id._type) {
|
||||
switch(_type) {
|
||||
case C25519:
|
||||
return (memcmp(_k.t0.pub.data,id._k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN) < 0);
|
||||
case P384:
|
||||
return (memcmp(_k.t1.pub,id._k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE) < 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline bool operator!=(const Identity &id) const { return !(*this == id); }
|
||||
inline bool operator>(const Identity &id) const { return (id < *this); }
|
||||
inline bool operator<=(const Identity &id) const { return !(id < *this); }
|
||||
inline bool operator>=(const Identity &id) const { return !(*this < id); }
|
||||
|
||||
inline unsigned long hashCode() const { return (unsigned long)_address.toInt(); }
|
||||
|
||||
private:
|
||||
Address _address;
|
||||
C25519::Public _publicKey;
|
||||
C25519::Private *_privateKey;
|
||||
union {
|
||||
struct {
|
||||
C25519::Public pub;
|
||||
C25519::Private priv;
|
||||
} t0;
|
||||
struct {
|
||||
uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE];
|
||||
uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE];
|
||||
} t1;
|
||||
} _k;
|
||||
Type _type;
|
||||
bool _hasPrivate;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include "SelfAwareness.hpp"
|
||||
#include "Salsa20.hpp"
|
||||
#include "SHA512.hpp"
|
||||
#include "World.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "CertificateOfMembership.hpp"
|
||||
#include "Capability.hpp"
|
||||
@ -368,30 +367,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
|
||||
RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now);
|
||||
}
|
||||
|
||||
// Get primary planet world ID and world timestamp if present
|
||||
uint64_t planetWorldId = 0;
|
||||
uint64_t planetWorldTimestamp = 0;
|
||||
if ((ptr + 16) <= size()) {
|
||||
planetWorldId = at<uint64_t>(ptr); ptr += 8;
|
||||
planetWorldTimestamp = at<uint64_t>(ptr); ptr += 8;
|
||||
}
|
||||
|
||||
std::vector< std::pair<uint64_t,uint64_t> > moonIdsAndTimestamps;
|
||||
if (ptr < size()) {
|
||||
// Remainder of packet, if present, is encrypted
|
||||
cryptField(peer->key(),ptr,size() - ptr);
|
||||
|
||||
// Get moon IDs and timestamps if present
|
||||
if ((ptr + 2) <= size()) {
|
||||
const unsigned int numMoons = at<uint16_t>(ptr); ptr += 2;
|
||||
for(unsigned int i=0;i<numMoons;++i) {
|
||||
if ((World::Type)(*this)[ptr++] == World::TYPE_MOON)
|
||||
moonIdsAndTimestamps.push_back(std::pair<uint64_t,uint64_t>(at<uint64_t>(ptr),at<uint64_t>(ptr + 8)));
|
||||
ptr += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send OK(HELLO) with an echo of the packet's timestamp and some of the same
|
||||
// information about us: version, sent-to address, etc.
|
||||
|
||||
@ -435,25 +410,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
|
||||
tmpa.serialize(outp);
|
||||
}
|
||||
|
||||
const unsigned int worldUpdateSizeAt = outp.size();
|
||||
outp.addSize(2); // make room for 16-bit size field
|
||||
if ((planetWorldId)&&(RR->topology->planetWorldTimestamp() > planetWorldTimestamp)&&(planetWorldId == RR->topology->planetWorldId())) {
|
||||
RR->topology->planet().serialize(outp,false);
|
||||
}
|
||||
if (moonIdsAndTimestamps.size() > 0) {
|
||||
std::vector<World> moons(RR->topology->moons());
|
||||
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
|
||||
for(std::vector< std::pair<uint64_t,uint64_t> >::const_iterator i(moonIdsAndTimestamps.begin());i!=moonIdsAndTimestamps.end();++i) {
|
||||
if (i->first == m->id()) {
|
||||
if (m->timestamp() > i->second)
|
||||
m->serialize(outp,false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
outp.setAt<uint16_t>(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2)));
|
||||
|
||||
outp.armor(peer->key(),true);
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||
|
||||
@ -489,22 +445,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
|
||||
// Get reported external surface address if present
|
||||
if (ptr < size())
|
||||
ptr += externalSurfaceAddress.deserialize(*this,ptr);
|
||||
|
||||
// Handle planet or moon updates if present
|
||||
if ((ptr + 2) <= size()) {
|
||||
const unsigned int worldsLen = at<uint16_t>(ptr); ptr += 2;
|
||||
if (RR->topology->shouldAcceptWorldUpdateFrom(peer->address())) {
|
||||
const unsigned int endOfWorlds = ptr + worldsLen;
|
||||
while (ptr < endOfWorlds) {
|
||||
World w;
|
||||
ptr += w.deserialize(*this,ptr);
|
||||
RR->topology->addWorld(tPtr,w,false);
|
||||
}
|
||||
} else {
|
||||
ptr += worldsLen;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hops()) {
|
||||
_path->updateLatency((unsigned int)latency,RR->node->now());
|
||||
}
|
||||
@ -575,8 +515,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
|
||||
|
||||
bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
if ((!RR->topology->amUpstream())&&(!peer->rateGateInboundWhoisRequest(RR->node->now())))
|
||||
return true;
|
||||
// TODO
|
||||
//if ((!RR->topology->amUpstream())&&(!peer->rateGateInboundWhoisRequest(RR->node->now())))
|
||||
// return true;
|
||||
|
||||
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
|
||||
outp.append((unsigned char)Packet::VERB_WHOIS);
|
||||
@ -772,8 +713,8 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c
|
||||
SharedPtr<Network> network(RR->node->network(nwid));
|
||||
if (network)
|
||||
authorized = network->gate(tPtr,peer);
|
||||
if (!authorized)
|
||||
authorized = ((RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())));
|
||||
//if (!authorized)
|
||||
// authorized = ((RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())));
|
||||
}
|
||||
if (authorized)
|
||||
RR->mc->add(tPtr,now,nwid,MulticastGroup(MAC(field(ptr + 8,6),6),at<uint32_t>(ptr + 14)),peer->address());
|
||||
@ -982,7 +923,8 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr
|
||||
}
|
||||
|
||||
const int64_t now = RR->node->now();
|
||||
if ((gatherLimit > 0)&&((trustEstablished)||(RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())))) {
|
||||
//if ((gatherLimit > 0)&&((trustEstablished)||(RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())))) {
|
||||
if (gatherLimit) {
|
||||
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
|
||||
outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER);
|
||||
outp.append(packetId());
|
||||
|
@ -93,7 +93,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
RR->identity.generate();
|
||||
RR->identity.generate(Identity::C25519);
|
||||
RR->identity.toString(false,RR->publicIdentityStr);
|
||||
RR->identity.toString(true,RR->secretIdentityStr);
|
||||
idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0;
|
||||
@ -192,16 +192,17 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
|
||||
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Closure used to ping upstream and active/online peers
|
||||
class _PingPeersThatNeedPing
|
||||
// Function object used to traverse the peer list, check peer status, and ping
|
||||
// those that need pinging.
|
||||
struct _PingPeersThatNeedPing
|
||||
{
|
||||
public:
|
||||
_PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector<InetAddress> > &alwaysContact,int64_t now) :
|
||||
RR(renv),
|
||||
_tPtr(tPtr),
|
||||
_alwaysContact(alwaysContact),
|
||||
_now(now),
|
||||
_bestCurrentUpstream(RR->topology->getUpstreamPeer())
|
||||
_bestCurrentUpstream(RR->topology->getUpstreamPeer()),
|
||||
online(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -209,6 +210,7 @@ public:
|
||||
{
|
||||
const std::vector<InetAddress> *const alwaysContactEndpoints = _alwaysContact.get(p->address());
|
||||
if (alwaysContactEndpoints) {
|
||||
online |= p->isAlive(_now);
|
||||
const unsigned int sent = p->doPingAndKeepalive(_tPtr,_now);
|
||||
bool contacted = (sent != 0);
|
||||
|
||||
@ -246,12 +248,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const RuntimeEnvironment *RR;
|
||||
void *_tPtr;
|
||||
Hashtable< Address,std::vector<InetAddress> > &_alwaysContact;
|
||||
const int64_t _now;
|
||||
const SharedPtr<Peer> _bestCurrentUpstream;
|
||||
|
||||
bool online;
|
||||
};
|
||||
|
||||
ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline)
|
||||
@ -265,38 +268,25 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
|
||||
try {
|
||||
_lastPingCheck = now;
|
||||
|
||||
// Get designated VL1 upstreams
|
||||
Hashtable< Address,std::vector<InetAddress> > alwaysContact;
|
||||
RR->topology->getUpstreamsToContact(alwaysContact);
|
||||
|
||||
// Check last receive time on designated upstreams to see if we seem to be online
|
||||
int64_t lastReceivedFromUpstream = 0;
|
||||
{
|
||||
Hashtable< Address,std::vector<InetAddress> >::Iterator i(alwaysContact);
|
||||
Address *upstreamAddress = (Address *)0;
|
||||
std::vector<InetAddress> *upstreamStableEndpoints = (std::vector<InetAddress> *)0;
|
||||
while (i.next(upstreamAddress,upstreamStableEndpoints)) {
|
||||
SharedPtr<Peer> p(RR->topology->getPeerNoCache(*upstreamAddress));
|
||||
if (p)
|
||||
lastReceivedFromUpstream = std::max(p->lastReceive(),lastReceivedFromUpstream);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up any old local controller auth memorizations.
|
||||
// Clean up any old local controller auth memoizations. This is an
|
||||
// optimization for network controllers to know whether to accept
|
||||
// or trust nodes without doing an extra cert check.
|
||||
{
|
||||
_localControllerAuthorizations_m.lock();
|
||||
Hashtable< _LocalControllerAuth,int64_t >::Iterator i(_localControllerAuthorizations);
|
||||
_LocalControllerAuth *k = (_LocalControllerAuth *)0;
|
||||
int64_t *v = (int64_t *)0;
|
||||
while (i.next(k,v)) {
|
||||
if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3))
|
||||
if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3)) {
|
||||
_localControllerAuthorizations.erase(*k);
|
||||
}
|
||||
}
|
||||
_localControllerAuthorizations_m.unlock();
|
||||
}
|
||||
|
||||
// Get peers we should stay connected to according to network configs
|
||||
// Also get networks and whether they need config so we only have to do one pass over networks
|
||||
// (1) Get peers we should remain connected to and (2) get networks that need config.
|
||||
Hashtable< Address,std::vector<InetAddress> > alwaysContact;
|
||||
RR->topology->getUpstreamsToContact(alwaysContact);
|
||||
std::vector< std::pair< SharedPtr<Network>,bool > > networkConfigNeeded;
|
||||
{
|
||||
Mutex::Lock l(_networks_m);
|
||||
@ -331,7 +321,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
|
||||
|
||||
// Update online status, post status change as event
|
||||
const bool oldOnline = _online;
|
||||
_online = (((now - lastReceivedFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amUpstream()));
|
||||
_online = pfunc.online;
|
||||
if (oldOnline != _online)
|
||||
postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
|
||||
} catch ( ... ) {
|
||||
@ -425,18 +415,6 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u
|
||||
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
|
||||
}
|
||||
|
||||
ZT_ResultCode Node::orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed)
|
||||
{
|
||||
RR->topology->addMoon(tptr,moonWorldId,Address(moonSeed));
|
||||
return ZT_RESULT_OK;
|
||||
}
|
||||
|
||||
ZT_ResultCode Node::deorbit(void *tptr,uint64_t moonWorldId)
|
||||
{
|
||||
RR->topology->removeMoon(tptr,moonWorldId);
|
||||
return ZT_RESULT_OK;
|
||||
}
|
||||
|
||||
uint64_t Node::address() const
|
||||
{
|
||||
return RR->identity.address().toInt();
|
||||
@ -635,16 +613,6 @@ ZT_ResultCode Node::setPhysicalPathConfiguration(const struct sockaddr_storage *
|
||||
return ZT_RESULT_OK;
|
||||
}
|
||||
|
||||
World Node::planet() const
|
||||
{
|
||||
return RR->topology->planet();
|
||||
}
|
||||
|
||||
std::vector<World> Node::moons() const
|
||||
{
|
||||
return RR->topology->moons();
|
||||
}
|
||||
|
||||
void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig)
|
||||
{
|
||||
_localControllerAuthorizations_m.lock();
|
||||
@ -682,10 +650,11 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de
|
||||
outp.append((uint32_t)totalSize);
|
||||
outp.append((uint32_t)chunkIndex);
|
||||
|
||||
C25519::Signature sig(RR->identity.sign(reinterpret_cast<const uint8_t *>(outp.data()) + sigStart,outp.size() - sigStart));
|
||||
uint8_t sig[256];
|
||||
const unsigned int siglen = RR->identity.sign(reinterpret_cast<const uint8_t *>(outp.data()) + sigStart,outp.size() - sigStart,sig,sizeof(sig));
|
||||
outp.append((uint8_t)1);
|
||||
outp.append((uint16_t)ZT_C25519_SIGNATURE_LEN);
|
||||
outp.append(sig.data,ZT_C25519_SIGNATURE_LEN);
|
||||
outp.append((uint16_t)siglen);
|
||||
outp.append(sig,siglen);
|
||||
|
||||
outp.compress();
|
||||
RR->sw->send((void *)0,outp,true);
|
||||
@ -879,24 +848,6 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint
|
||||
}
|
||||
}
|
||||
|
||||
enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed)
|
||||
{
|
||||
try {
|
||||
return reinterpret_cast<ZeroTier::Node *>(node)->orbit(tptr,moonWorldId,moonSeed);
|
||||
} catch ( ... ) {
|
||||
return ZT_RESULT_FATAL_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId)
|
||||
{
|
||||
try {
|
||||
return reinterpret_cast<ZeroTier::Node *>(node)->deorbit(tptr,moonWorldId);
|
||||
} catch ( ... ) {
|
||||
return ZT_RESULT_FATAL_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ZT_Node_address(ZT_Node *node)
|
||||
{
|
||||
return reinterpret_cast<ZeroTier::Node *>(node)->address();
|
||||
|
@ -54,8 +54,6 @@
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class World;
|
||||
|
||||
/**
|
||||
* Implementation of Node object as defined in CAPI
|
||||
*
|
||||
@ -99,8 +97,6 @@ public:
|
||||
ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr);
|
||||
ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
|
||||
ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
|
||||
ZT_ResultCode orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed);
|
||||
ZT_ResultCode deorbit(void *tptr,uint64_t moonWorldId);
|
||||
uint64_t address() const;
|
||||
void status(ZT_NodeStatus *status) const;
|
||||
ZT_PeerList *peers() const;
|
||||
@ -194,9 +190,6 @@ public:
|
||||
uint64_t prng();
|
||||
ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
|
||||
|
||||
World planet() const;
|
||||
std::vector<World> moons() const;
|
||||
|
||||
inline const Identity &identity() const { return _RR.identity; }
|
||||
|
||||
/**
|
||||
|
@ -972,16 +972,6 @@ bool Packet::dearmor(const void *key)
|
||||
}
|
||||
}
|
||||
|
||||
void Packet::cryptField(const void *key,unsigned int start,unsigned int len)
|
||||
{
|
||||
uint8_t *const data = reinterpret_cast<uint8_t *>(unsafeData());
|
||||
uint8_t iv[8];
|
||||
for(int i=0;i<8;++i) iv[i] = data[i];
|
||||
iv[7] &= 0xf8; // mask off least significant 3 bits of packet ID / IV since this is unset when this function gets called
|
||||
Salsa20 s20(key,iv);
|
||||
s20.crypt12(data + start,data + start,len);
|
||||
}
|
||||
|
||||
bool Packet::compress()
|
||||
{
|
||||
char *const data = reinterpret_cast<char *>(unsafeData());
|
||||
|
@ -71,6 +71,7 @@
|
||||
* 10 - 1.4.0 ... CURRENT
|
||||
* + Multipath capability and load balancing
|
||||
* + Peer-to-peer multicast replication (optional)
|
||||
* + Old planet/moon stuff is DEAD!
|
||||
*/
|
||||
#define ZT_PROTO_VERSION 10
|
||||
|
||||
@ -532,22 +533,9 @@ public:
|
||||
* <[8] timestamp for determining latency>
|
||||
* <[...] binary serialized identity (see Identity)>
|
||||
* <[...] physical destination address of packet>
|
||||
* <[8] 64-bit world ID of current planet>
|
||||
* <[8] 64-bit timestamp of current planet>
|
||||
* [... remainder if packet is encrypted using cryptField() ...]
|
||||
* <[2] 16-bit number of moons>
|
||||
* [<[1] 8-bit type ID of moon>]
|
||||
* [<[8] 64-bit world ID of moon>]
|
||||
* [<[8] 64-bit timestamp of moon>]
|
||||
* [... additional moon type/ID/timestamp tuples ...]
|
||||
*
|
||||
*
|
||||
* HELLO is sent in the clear as it is how peers share their identity
|
||||
* public keys. A few additional fields are sent in the clear too, but
|
||||
* these are things that are public info or are easy to determine. As
|
||||
* of 1.2.0 we have added a few more fields, but since these could have
|
||||
* the potential to be sensitive we introduced the encryption of the
|
||||
* remainder of the packet. See cryptField(). Packet MAC is still
|
||||
* performed of course, so authentication occurs as normal.
|
||||
* public keys.
|
||||
*
|
||||
* Destination address is the actual wire address to which the packet
|
||||
* was sent. See InetAddress::serialize() for format.
|
||||
@ -559,15 +547,10 @@ public:
|
||||
* <[1] software minor version>
|
||||
* <[2] software revision>
|
||||
* <[...] physical destination address of packet>
|
||||
* <[2] 16-bit length of world update(s) or 0 if none>
|
||||
* [[...] updates to planets and/or moons]
|
||||
*
|
||||
* With the exception of the timestamp, the other fields pertain to the
|
||||
* respondent who is sending OK and are not echoes.
|
||||
*
|
||||
* Note that OK is fully encrypted so no selective cryptField() of
|
||||
* potentially sensitive fields is needed.
|
||||
*
|
||||
* ERROR has no payload.
|
||||
*/
|
||||
VERB_HELLO = 0x01,
|
||||
@ -1268,21 +1251,6 @@ public:
|
||||
*/
|
||||
bool dearmor(const void *key);
|
||||
|
||||
/**
|
||||
* Encrypt/decrypt a separately armored portion of a packet
|
||||
*
|
||||
* This is currently only used to mask portions of HELLO as an extra
|
||||
* security precaution since most of that message is sent in the clear.
|
||||
*
|
||||
* This must NEVER be used more than once in the same packet, as doing
|
||||
* so will result in re-use of the same key stream.
|
||||
*
|
||||
* @param key 32-byte key
|
||||
* @param start Start of encrypted portion
|
||||
* @param len Length of encrypted portion
|
||||
*/
|
||||
void cryptField(const void *key,unsigned int start,unsigned int len);
|
||||
|
||||
/**
|
||||
* Attempt to compress payload if not already (must be unencrypted)
|
||||
*
|
||||
|
@ -711,27 +711,6 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
|
||||
RR->identity.serialize(outp,false);
|
||||
atAddress.serialize(outp);
|
||||
|
||||
outp.append((uint64_t)RR->topology->planetWorldId());
|
||||
outp.append((uint64_t)RR->topology->planetWorldTimestamp());
|
||||
|
||||
const unsigned int startCryptedPortionAt = outp.size();
|
||||
|
||||
std::vector<World> moons(RR->topology->moons());
|
||||
std::vector<uint64_t> moonsWanted(RR->topology->moonsWanted());
|
||||
outp.append((uint16_t)(moons.size() + moonsWanted.size()));
|
||||
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
|
||||
outp.append((uint8_t)m->type());
|
||||
outp.append((uint64_t)m->id());
|
||||
outp.append((uint64_t)m->timestamp());
|
||||
}
|
||||
for(std::vector<uint64_t>::const_iterator m(moonsWanted.begin());m!=moonsWanted.end();++m) {
|
||||
outp.append((uint8_t)World::TYPE_MOON);
|
||||
outp.append(*m);
|
||||
outp.append((uint64_t)0);
|
||||
}
|
||||
|
||||
outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt);
|
||||
|
||||
RR->node->expectReplyTo(outp.packetId());
|
||||
|
||||
if (atAddress) {
|
||||
|
@ -34,6 +34,18 @@
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
bool Revocation::sign(const Identity &signer)
|
||||
{
|
||||
if (signer.hasPrivate()) {
|
||||
Buffer<sizeof(Revocation) + 64> tmp;
|
||||
_signedBy = signer.address();
|
||||
this->serialize(tmp,true);
|
||||
_signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const
|
||||
{
|
||||
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
|
||||
@ -46,7 +58,7 @@ int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const
|
||||
try {
|
||||
Buffer<sizeof(Revocation) + 64> tmp;
|
||||
this->serialize(tmp,true);
|
||||
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
|
||||
return (id.verify(tmp.data(),tmp.size(),_signature,_signatureLength) ? 0 : -1);
|
||||
} catch ( ... ) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -66,9 +66,9 @@ public:
|
||||
_flags(0),
|
||||
_target(),
|
||||
_signedBy(),
|
||||
_type(Credential::CREDENTIAL_TYPE_NULL)
|
||||
_type(Credential::CREDENTIAL_TYPE_NULL),
|
||||
_signatureLength(0)
|
||||
{
|
||||
memset(_signature.data,0,sizeof(_signature.data));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,9 +88,9 @@ public:
|
||||
_flags(fl),
|
||||
_target(tgt),
|
||||
_signedBy(),
|
||||
_type(ct)
|
||||
_type(ct),
|
||||
_signatureLength(0)
|
||||
{
|
||||
memset(_signature.data,0,sizeof(_signature.data));
|
||||
}
|
||||
|
||||
inline uint32_t id() const { return _id; }
|
||||
@ -107,17 +107,7 @@ public:
|
||||
* @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;
|
||||
}
|
||||
bool sign(const Identity &signer);
|
||||
|
||||
/**
|
||||
* Verify this revocation's signature
|
||||
@ -145,9 +135,9 @@ public:
|
||||
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);
|
||||
b.append((uint8_t)1);
|
||||
b.append((uint16_t)_signatureLength);
|
||||
b.append(_signature,_signatureLength);
|
||||
}
|
||||
|
||||
// This is the size of any additional fields, currently 0.
|
||||
@ -175,11 +165,10 @@ public:
|
||||
_type = (Credential::Type)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 ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
|
||||
_signatureLength = b.template at<uint16_t>(p);
|
||||
if (_signatureLength > sizeof(_signature))
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
|
||||
memcpy(_signature,b.field(p,_signatureLength),_signatureLength);
|
||||
} else {
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
}
|
||||
@ -200,7 +189,8 @@ private:
|
||||
Address _target;
|
||||
Address _signedBy;
|
||||
Credential::Type _type;
|
||||
C25519::Signature _signature;
|
||||
unsigned int _signatureLength;
|
||||
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -92,9 +92,6 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
||||
const Address destination(fragment.destination());
|
||||
|
||||
if (destination != RR->identity.address()) {
|
||||
if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) )
|
||||
return;
|
||||
|
||||
if (fragment.hops() < ZT_RELAY_MAX_HOPS) {
|
||||
fragment.incrementHops();
|
||||
|
||||
@ -164,11 +161,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
||||
return;
|
||||
|
||||
if (destination != RR->identity.address()) {
|
||||
if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) && (source != RR->identity.address()) )
|
||||
return;
|
||||
|
||||
Packet packet(data,len);
|
||||
|
||||
if (packet.hops() < ZT_RELAY_MAX_HOPS) {
|
||||
packet.incrementHops();
|
||||
SharedPtr<Peer> relayTo = RR->topology->getPeer(tPtr,destination);
|
||||
|
14
node/Tag.cpp
14
node/Tag.cpp
@ -34,6 +34,18 @@
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
bool Tag::sign(const Identity &signer)
|
||||
{
|
||||
if (signer.hasPrivate()) {
|
||||
Buffer<sizeof(Tag) + 64> tmp;
|
||||
_signedBy = signer.address();
|
||||
this->serialize(tmp,true);
|
||||
_signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const
|
||||
{
|
||||
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
|
||||
@ -46,7 +58,7 @@ int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const
|
||||
try {
|
||||
Buffer<(sizeof(Tag) * 2)> tmp;
|
||||
this->serialize(tmp,true);
|
||||
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
|
||||
return (id.verify(tmp.data(),tmp.size(),_signature,_signatureLength) ? 0 : -1);
|
||||
} catch ( ... ) {
|
||||
return -1;
|
||||
}
|
||||
|
34
node/Tag.hpp
34
node/Tag.hpp
@ -69,9 +69,9 @@ public:
|
||||
_id(0),
|
||||
_value(0),
|
||||
_networkId(0),
|
||||
_ts(0)
|
||||
_ts(0),
|
||||
_signatureLength(0)
|
||||
{
|
||||
memset(_signature.data,0,sizeof(_signature.data));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,9 +87,9 @@ public:
|
||||
_networkId(nwid),
|
||||
_ts(ts),
|
||||
_issuedTo(issuedTo),
|
||||
_signedBy()
|
||||
_signedBy(),
|
||||
_signatureLength(0)
|
||||
{
|
||||
memset(_signature.data,0,sizeof(_signature.data));
|
||||
}
|
||||
|
||||
inline uint32_t id() const { return _id; }
|
||||
@ -105,17 +105,7 @@ public:
|
||||
* @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;
|
||||
}
|
||||
bool sign(const Identity &signer);
|
||||
|
||||
/**
|
||||
* Check this tag's signature
|
||||
@ -139,9 +129,9 @@ public:
|
||||
_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((uint8_t)1);
|
||||
b.append((uint16_t)_signatureLength);
|
||||
b.append(_signature,_signatureLength);
|
||||
}
|
||||
|
||||
b.append((uint16_t)0); // length of additional fields, currently 0
|
||||
@ -165,10 +155,11 @@ public:
|
||||
_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)
|
||||
_signatureLength = b.template at<uint16_t>(p);
|
||||
if (_signatureLength > sizeof(_signature))
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
|
||||
p += 2;
|
||||
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
|
||||
memcpy(_signature,b.field(p,_signatureLength),_signatureLength); p += _signatureLength;
|
||||
} else {
|
||||
p += 2 + b.template at<uint16_t>(p);
|
||||
}
|
||||
@ -207,7 +198,8 @@ private:
|
||||
int64_t _ts;
|
||||
Address _issuedTo;
|
||||
Address _signedBy;
|
||||
C25519::Signature _signature;
|
||||
unsigned int _signatureLength;
|
||||
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -35,57 +35,10 @@
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/*
|
||||
* 2018-07-26 ZeroTier planet definition for the third planet of Sol:
|
||||
*
|
||||
* There are two roots, each of which is a cluster spread across multiple
|
||||
* continents and providers. They are named Alice and Bob after the
|
||||
* canonical example names used in cryptography.
|
||||
*
|
||||
* Alice:
|
||||
*
|
||||
* root-alice-ams-01: Amsterdam, Netherlands
|
||||
* root-alice-joh-01: Johannesburg, South Africa
|
||||
* root-alice-nyc-01: New York, New York, USA
|
||||
* root-alice-arg-01: Buenos Aires, Argentina
|
||||
* root-alice-sfo-01: San Francisco, California, USA
|
||||
* root-alice-sgp-01: Singapore
|
||||
*
|
||||
* Bob:
|
||||
*
|
||||
* root-bob-dfw-01: Dallas, Texas, USA
|
||||
* root-bob-fra-01: Frankfurt, Germany
|
||||
* root-bob-par-01: Paris, France
|
||||
* root-bob-syd-01: Sydney, Australia
|
||||
* root-bob-tok-01: Tokyo, Japan
|
||||
* root-bob-tor-01: Toronto, Canada
|
||||
*/
|
||||
#define ZT_DEFAULT_WORLD_LENGTH 634
|
||||
static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x64,0xd3,0x71,0xf0,0x58,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0xbf,0xfd,0xd5,0x32,0xf7,0x15,0x6e,0x02,0x6f,0xb9,0x01,0x0d,0xb5,0x7b,0x04,0xd8,0x3a,0xc5,0x17,0x39,0x04,0x36,0xfd,0x9d,0xc6,0x3d,0xa8,0xf3,0x8e,0x79,0xe7,0xc8,0x77,0x8d,0xcc,0x79,0xb8,0xab,0xc6,0x98,0x7c,0x9f,0x34,0x25,0x14,0xe1,0x2f,0xd7,0x97,0x11,0xec,0x34,0x4c,0x9f,0x0f,0xb4,0x85,0x0d,0x9b,0x11,0xd1,0xc2,0xce,0x00,0xc4,0x0a,0x13,0x4b,0xcb,0xc3,0xae,0x2e,0x16,0x00,0x4b,0xdc,0x90,0x5e,0x7e,0x9b,0x44,0x07,0x15,0x36,0x61,0x3c,0x64,0xaa,0xe9,0x46,0x78,0x3c,0xa7,0x18,0xc8,0xd8,0x02,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x7d,0x00,0x01,0x00,0x00,0x00,0x00,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x33,0xcc,0x08,0xf8,0xfa,0xcc,0x08,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x54,0x60,0x01,0x00,0xfc,0xcc,0x08,0x27,0x09,0x04,0x83,0xff,0x06,0x10,0x27,0x09,0x06,0x28,0x03,0xeb,0x80,0x00,0x00,0x00,0x0e,0x00,0x02,0x60,0x01,0x00,0xfc,0xcc,0x08,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x02,0x00,0xe0,0x01,0x08,0xfe,0xcc,0x08,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0xb7,0x40,0x01,0x08,0xfe,0xcc,0x08,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x6a,0x30,0x01,0x78,0x00,0xcd,0x08,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x64,0xcd,0x08,0x80,0x01,0xcd,0x08,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x26,0x70,0x01,0xfe,0x15,0xc4,0xf5,0x27,0x09};
|
||||
|
||||
Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) :
|
||||
RR(renv),
|
||||
_numConfiguredPhysicalPaths(0),
|
||||
_amUpstream(false)
|
||||
_numConfiguredPhysicalPaths(0)
|
||||
{
|
||||
uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
|
||||
uint64_t idtmp[2];
|
||||
idtmp[0] = 0; idtmp[1] = 0;
|
||||
int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PLANET,idtmp,tmp,sizeof(tmp));
|
||||
if (n > 0) {
|
||||
try {
|
||||
World cachedPlanet;
|
||||
cachedPlanet.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp,(unsigned int)n),0);
|
||||
addWorld(tPtr,cachedPlanet,false);
|
||||
} catch ( ... ) {} // ignore invalid cached planets
|
||||
}
|
||||
|
||||
World defaultPlanet;
|
||||
{
|
||||
Buffer<ZT_DEFAULT_WORLD_LENGTH> wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH);
|
||||
defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top
|
||||
}
|
||||
addWorld(tPtr,defaultPlanet,false);
|
||||
}
|
||||
|
||||
Topology::~Topology()
|
||||
@ -158,224 +111,33 @@ Identity Topology::getIdentity(void *tPtr,const Address &zta)
|
||||
|
||||
SharedPtr<Peer> Topology::getUpstreamPeer()
|
||||
{
|
||||
const int64_t now = RR->node->now();
|
||||
unsigned int bestq = ~((unsigned int)0);
|
||||
const SharedPtr<Peer> *best = (const SharedPtr<Peer> *)0;
|
||||
|
||||
Mutex::Lock _l2(_peers_m);
|
||||
Mutex::Lock _l1(_upstreams_m);
|
||||
|
||||
for(std::vector<Address>::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) {
|
||||
const SharedPtr<Peer> *p = _peers.get(*a);
|
||||
if (p) {
|
||||
const unsigned int q = (*p)->relayQuality(now);
|
||||
if (q <= bestq) {
|
||||
bestq = q;
|
||||
best = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!best)
|
||||
return SharedPtr<Peer>();
|
||||
return *best;
|
||||
return SharedPtr<Peer>();
|
||||
}
|
||||
|
||||
bool Topology::isUpstream(const Identity &id) const
|
||||
{
|
||||
Mutex::Lock _l(_upstreams_m);
|
||||
return (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) != _upstreamAddresses.end());
|
||||
}
|
||||
|
||||
bool Topology::shouldAcceptWorldUpdateFrom(const Address &addr) const
|
||||
{
|
||||
Mutex::Lock _l(_upstreams_m);
|
||||
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),addr) != _upstreamAddresses.end())
|
||||
return true;
|
||||
for(std::vector< std::pair< uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) {
|
||||
if (s->second == addr)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ZT_PeerRole Topology::role(const Address &ztaddr) const
|
||||
{
|
||||
Mutex::Lock _l(_upstreams_m);
|
||||
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) {
|
||||
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
|
||||
if (i->identity.address() == ztaddr)
|
||||
return ZT_PEER_ROLE_PLANET;
|
||||
}
|
||||
return ZT_PEER_ROLE_MOON;
|
||||
}
|
||||
return ZT_PEER_ROLE_LEAF;
|
||||
}
|
||||
|
||||
bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const
|
||||
{
|
||||
Mutex::Lock _l(_upstreams_m);
|
||||
|
||||
// For roots the only permitted addresses are those defined. This adds just a little
|
||||
// bit of extra security against spoofing, replaying, etc.
|
||||
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) {
|
||||
for(std::vector<World::Root>::const_iterator r(_planet.roots().begin());r!=_planet.roots().end();++r) {
|
||||
if (r->identity.address() == ztaddr) {
|
||||
if (r->stableEndpoints.size() == 0)
|
||||
return false; // no stable endpoints specified, so allow dynamic paths
|
||||
for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) {
|
||||
if (ipaddr.ipsEqual(*e))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
|
||||
for(std::vector<World::Root>::const_iterator r(m->roots().begin());r!=m->roots().end();++r) {
|
||||
if (r->identity.address() == ztaddr) {
|
||||
if (r->stableEndpoints.size() == 0)
|
||||
return false; // no stable endpoints specified, so allow dynamic paths
|
||||
for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) {
|
||||
if (ipaddr.ipsEqual(*e))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
|
||||
{
|
||||
if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON))
|
||||
return false;
|
||||
|
||||
Mutex::Lock _l2(_peers_m);
|
||||
Mutex::Lock _l1(_upstreams_m);
|
||||
|
||||
World *existing = (World *)0;
|
||||
switch(newWorld.type()) {
|
||||
case World::TYPE_PLANET:
|
||||
existing = &_planet;
|
||||
break;
|
||||
case World::TYPE_MOON:
|
||||
for(std::vector< World >::iterator m(_moons.begin());m!=_moons.end();++m) {
|
||||
if (m->id() == newWorld.id()) {
|
||||
existing = &(*m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (existing) {
|
||||
if (existing->shouldBeReplacedBy(newWorld))
|
||||
*existing = newWorld;
|
||||
else return false;
|
||||
} else if (newWorld.type() == World::TYPE_MOON) {
|
||||
if (alwaysAcceptNew) {
|
||||
_moons.push_back(newWorld);
|
||||
existing = &(_moons.back());
|
||||
} else {
|
||||
for(std::vector< std::pair<uint64_t,Address> >::iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) {
|
||||
if (m->first == newWorld.id()) {
|
||||
for(std::vector<World::Root>::const_iterator r(newWorld.roots().begin());r!=newWorld.roots().end();++r) {
|
||||
if (r->identity.address() == m->second) {
|
||||
_moonSeeds.erase(m);
|
||||
_moons.push_back(newWorld);
|
||||
existing = &(_moons.back());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (existing)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!existing)
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> sbuf;
|
||||
existing->serialize(sbuf,false);
|
||||
uint64_t idtmp[2];
|
||||
idtmp[0] = existing->id(); idtmp[1] = 0;
|
||||
RR->node->stateObjectPut(tPtr,(existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON,idtmp,sbuf.data(),sbuf.size());
|
||||
} catch ( ... ) {}
|
||||
|
||||
_memoizeUpstreams(tPtr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed)
|
||||
{
|
||||
char tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
|
||||
uint64_t idtmp[2];
|
||||
idtmp[0] = id; idtmp[1] = 0;
|
||||
int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_MOON,idtmp,tmp,sizeof(tmp));
|
||||
if (n > 0) {
|
||||
try {
|
||||
World w;
|
||||
w.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp,(unsigned int)n));
|
||||
if ((w.type() == World::TYPE_MOON)&&(w.id() == id)) {
|
||||
addWorld(tPtr,w,true);
|
||||
return;
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
|
||||
if (seed) {
|
||||
Mutex::Lock _l(_upstreams_m);
|
||||
if (std::find(_moonSeeds.begin(),_moonSeeds.end(),std::pair<uint64_t,Address>(id,seed)) == _moonSeeds.end())
|
||||
_moonSeeds.push_back(std::pair<uint64_t,Address>(id,seed));
|
||||
}
|
||||
}
|
||||
|
||||
void Topology::removeMoon(void *tPtr,const uint64_t id)
|
||||
{
|
||||
Mutex::Lock _l2(_peers_m);
|
||||
Mutex::Lock _l1(_upstreams_m);
|
||||
|
||||
std::vector<World> nm;
|
||||
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
|
||||
if (m->id() != id) {
|
||||
nm.push_back(*m);
|
||||
} else {
|
||||
uint64_t idtmp[2];
|
||||
idtmp[0] = id; idtmp[1] = 0;
|
||||
RR->node->stateObjectDelete(tPtr,ZT_STATE_OBJECT_MOON,idtmp);
|
||||
}
|
||||
}
|
||||
_moons.swap(nm);
|
||||
|
||||
std::vector< std::pair<uint64_t,Address> > cm;
|
||||
for(std::vector< std::pair<uint64_t,Address> >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) {
|
||||
if (m->first != id)
|
||||
cm.push_back(*m);
|
||||
}
|
||||
_moonSeeds.swap(cm);
|
||||
|
||||
_memoizeUpstreams(tPtr);
|
||||
}
|
||||
|
||||
void Topology::doPeriodicTasks(void *tPtr,int64_t now)
|
||||
{
|
||||
{
|
||||
Mutex::Lock _l1(_peers_m);
|
||||
Mutex::Lock _l2(_upstreams_m);
|
||||
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
|
||||
Address *a = (Address *)0;
|
||||
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
|
||||
while (i.next(a,p)) {
|
||||
if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) {
|
||||
if (!(*p)->isAlive(now)) {
|
||||
_savePeer(tPtr,*p);
|
||||
_peers.erase(*a);
|
||||
}
|
||||
@ -394,39 +156,6 @@ void Topology::doPeriodicTasks(void *tPtr,int64_t now)
|
||||
}
|
||||
}
|
||||
|
||||
void Topology::_memoizeUpstreams(void *tPtr)
|
||||
{
|
||||
// assumes _upstreams_m and _peers_m are locked
|
||||
_upstreamAddresses.clear();
|
||||
_amUpstream = false;
|
||||
|
||||
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
|
||||
if (i->identity == RR->identity) {
|
||||
_amUpstream = true;
|
||||
} else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) {
|
||||
_upstreamAddresses.push_back(i->identity.address());
|
||||
SharedPtr<Peer> &hp = _peers[i->identity.address()];
|
||||
if (!hp)
|
||||
hp = new Peer(RR,RR->identity,i->identity);
|
||||
}
|
||||
}
|
||||
|
||||
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
|
||||
for(std::vector<World::Root>::const_iterator i(m->roots().begin());i!=m->roots().end();++i) {
|
||||
if (i->identity == RR->identity) {
|
||||
_amUpstream = true;
|
||||
} else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) {
|
||||
_upstreamAddresses.push_back(i->identity.address());
|
||||
SharedPtr<Peer> &hp = _peers[i->identity.address()];
|
||||
if (!hp)
|
||||
hp = new Peer(RR,RR->identity,i->identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end());
|
||||
}
|
||||
|
||||
void Topology::_savePeer(void *tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
try {
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include "Mutex.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
#include "Hashtable.hpp"
|
||||
#include "World.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
@ -136,12 +135,6 @@ public:
|
||||
*/
|
||||
bool isUpstream(const Identity &id) const;
|
||||
|
||||
/**
|
||||
* @param addr Address to check
|
||||
* @return True if we should accept a world update from this address
|
||||
*/
|
||||
bool shouldAcceptWorldUpdateFrom(const Address &addr) const;
|
||||
|
||||
/**
|
||||
* @param ztaddr ZeroTier address
|
||||
* @return Peer role for this device
|
||||
@ -171,29 +164,6 @@ public:
|
||||
*/
|
||||
inline void getUpstreamsToContact(Hashtable< Address,std::vector<InetAddress> > &eps) const
|
||||
{
|
||||
Mutex::Lock _l(_upstreams_m);
|
||||
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
|
||||
if (i->identity != RR->identity) {
|
||||
std::vector<InetAddress> &ips = eps[i->identity.address()];
|
||||
for(std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) {
|
||||
if (std::find(ips.begin(),ips.end(),*j) == ips.end())
|
||||
ips.push_back(*j);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
|
||||
for(std::vector<World::Root>::const_iterator i(m->roots().begin());i!=m->roots().end();++i) {
|
||||
if (i->identity != RR->identity) {
|
||||
std::vector<InetAddress> &ips = eps[i->identity.address()];
|
||||
for(std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) {
|
||||
if (std::find(ips.begin(),ips.end(),*j) == ips.end())
|
||||
ips.push_back(*j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(std::vector< std::pair<uint64_t,Address> >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m)
|
||||
eps[m->second];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -201,87 +171,9 @@ public:
|
||||
*/
|
||||
inline std::vector<Address> upstreamAddresses() const
|
||||
{
|
||||
Mutex::Lock _l(_upstreams_m);
|
||||
return _upstreamAddresses;
|
||||
return std::vector<Address>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current moons
|
||||
*/
|
||||
inline std::vector<World> moons() const
|
||||
{
|
||||
Mutex::Lock _l(_upstreams_m);
|
||||
return _moons;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Moon IDs we are waiting for from seeds
|
||||
*/
|
||||
inline std::vector<uint64_t> moonsWanted() const
|
||||
{
|
||||
Mutex::Lock _l(_upstreams_m);
|
||||
std::vector<uint64_t> mw;
|
||||
for(std::vector< std::pair<uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) {
|
||||
if (std::find(mw.begin(),mw.end(),s->first) == mw.end())
|
||||
mw.push_back(s->first);
|
||||
}
|
||||
return mw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current planet
|
||||
*/
|
||||
inline World planet() const
|
||||
{
|
||||
Mutex::Lock _l(_upstreams_m);
|
||||
return _planet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current planet's world ID
|
||||
*/
|
||||
inline uint64_t planetWorldId() const
|
||||
{
|
||||
return _planet.id(); // safe to read without lock, and used from within eachPeer() so don't lock
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current planet's world timestamp
|
||||
*/
|
||||
inline uint64_t planetWorldTimestamp() const
|
||||
{
|
||||
return _planet.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate new world and update if newer and signature is okay
|
||||
*
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param newWorld A new or updated planet or moon to learn
|
||||
* @param alwaysAcceptNew If true, always accept new moons even if we're not waiting for one
|
||||
* @return True if it was valid and newer than current (or totally new for moons)
|
||||
*/
|
||||
bool addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew);
|
||||
|
||||
/**
|
||||
* Add a moon
|
||||
*
|
||||
* This loads it from moons.d if present, and if not adds it to
|
||||
* a list of moons that we want to contact.
|
||||
*
|
||||
* @param id Moon ID
|
||||
* @param seed If non-NULL, an address of any member of the moon to contact
|
||||
*/
|
||||
void addMoon(void *tPtr,const uint64_t id,const Address &seed);
|
||||
|
||||
/**
|
||||
* Remove a moon
|
||||
*
|
||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param id Moon's world ID
|
||||
*/
|
||||
void removeMoon(void *tPtr,const uint64_t id);
|
||||
|
||||
/**
|
||||
* Clean and flush database
|
||||
*/
|
||||
@ -333,11 +225,6 @@ public:
|
||||
return _peers.entries();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if I am a root server in a planet or moon
|
||||
*/
|
||||
inline bool amUpstream() const { return _amUpstream; }
|
||||
|
||||
/**
|
||||
* Get info about a path
|
||||
*
|
||||
@ -455,13 +342,6 @@ private:
|
||||
|
||||
Hashtable< Path::HashKey,SharedPtr<Path> > _paths;
|
||||
Mutex _paths_m;
|
||||
|
||||
World _planet;
|
||||
std::vector<World> _moons;
|
||||
std::vector< std::pair<uint64_t,Address> > _moonSeeds;
|
||||
std::vector<Address> _upstreamAddresses;
|
||||
bool _amUpstream;
|
||||
Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc.
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -453,7 +453,7 @@ public:
|
||||
out[6] = BASE32CHARS[(in[3] & 0x03) << 3 | (in[4] & 0xe0) >> 5];
|
||||
out[7] = BASE32CHARS[(in[4] & 0x1f)];
|
||||
}
|
||||
|
||||
|
||||
static inline void base328to5(const char *const in,uint8_t *const out)
|
||||
{
|
||||
out[0] = ((BASE32BITS[(unsigned int)in[0]]) << 3) | (BASE32BITS[(unsigned int)in[1]] & 0x1C) >> 2;
|
||||
@ -462,7 +462,7 @@ public:
|
||||
out[3] = ((BASE32BITS[(unsigned int)in[4]] & 0x01) << 7) | (BASE32BITS[(unsigned int)in[5]]) << 2 | (BASE32BITS[(unsigned int)in[6]] & 0x18) >> 3;
|
||||
out[4] = ((BASE32BITS[(unsigned int)in[6]] & 0x07) << 5) | (BASE32BITS[(unsigned int)in[7]]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hexadecimal characters 0-f
|
||||
*/
|
||||
|
284
node/World.hpp
284
node/World.hpp
@ -1,284 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2019 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/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_WORLD_HPP
|
||||
#define ZT_WORLD_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "C25519.hpp"
|
||||
|
||||
/**
|
||||
* Maximum number of roots (sanity limit, okay to increase)
|
||||
*
|
||||
* A given root can (through multi-homing) be distributed across any number of
|
||||
* physical endpoints, but having more than one is good to permit total failure
|
||||
* of one root or its withdrawal due to compromise without taking the whole net
|
||||
* down.
|
||||
*/
|
||||
#define ZT_WORLD_MAX_ROOTS 4
|
||||
|
||||
/**
|
||||
* Maximum number of stable endpoints per root (sanity limit, okay to increase)
|
||||
*/
|
||||
#define ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT 32
|
||||
|
||||
/**
|
||||
* The (more than) maximum length of a serialized World
|
||||
*/
|
||||
#define ZT_WORLD_MAX_SERIALIZED_LENGTH (((1024 + (32 * ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)) * ZT_WORLD_MAX_ROOTS) + ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_SIGNATURE_LEN + 128)
|
||||
|
||||
/**
|
||||
* World ID for Earth
|
||||
*
|
||||
* This is the ID for the ZeroTier World used on planet Earth. It is unrelated
|
||||
* to the public network 8056c2e21c000001 of the same name. It was chosen
|
||||
* from Earth's approximate distance from the sun in kilometers.
|
||||
*/
|
||||
#define ZT_WORLD_ID_EARTH 149604618
|
||||
|
||||
/**
|
||||
* World ID for Mars -- for future use by SpaceX or others
|
||||
*/
|
||||
#define ZT_WORLD_ID_MARS 227883110
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* A world definition (formerly known as a root topology)
|
||||
*
|
||||
* Think of a World as a single data center. Within this data center a set
|
||||
* of distributed fault tolerant root servers provide stable anchor points
|
||||
* for a peer to peer network that provides VLAN service. Updates to a world
|
||||
* definition can be published by signing them with the previous revision's
|
||||
* signing key, and should be very infrequent.
|
||||
*
|
||||
* The maximum data center size is approximately 2.5 cubic light seconds,
|
||||
* since many protocols have issues with >5s RTT latencies.
|
||||
*
|
||||
* ZeroTier operates a World for Earth capable of encompassing the planet, its
|
||||
* orbits, the Moon (about 1.3 light seconds), and nearby Lagrange points. A
|
||||
* world ID for Mars and nearby space is defined but not yet used, and a test
|
||||
* world ID is provided for testing purposes.
|
||||
*/
|
||||
class World
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* World type -- do not change IDs
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
TYPE_NULL = 0,
|
||||
TYPE_PLANET = 1, // Planets, of which there is currently one (Earth)
|
||||
TYPE_MOON = 127 // Moons, which are user-created and many
|
||||
};
|
||||
|
||||
/**
|
||||
* Upstream server definition in world/moon
|
||||
*/
|
||||
struct Root
|
||||
{
|
||||
Identity identity;
|
||||
std::vector<InetAddress> stableEndpoints;
|
||||
|
||||
inline bool operator==(const Root &r) const { return ((identity == r.identity)&&(stableEndpoints == r.stableEndpoints)); }
|
||||
inline bool operator!=(const Root &r) const { return (!(*this == r)); }
|
||||
inline bool operator<(const Root &r) const { return (identity < r.identity); } // for sorting
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct an empty / null World
|
||||
*/
|
||||
World() :
|
||||
_id(0),
|
||||
_ts(0),
|
||||
_type(TYPE_NULL) {}
|
||||
|
||||
/**
|
||||
* @return Root servers for this world and their stable endpoints
|
||||
*/
|
||||
inline const std::vector<World::Root> &roots() const { return _roots; }
|
||||
|
||||
/**
|
||||
* @return World type: planet or moon
|
||||
*/
|
||||
inline Type type() const { return _type; }
|
||||
|
||||
/**
|
||||
* @return World unique identifier
|
||||
*/
|
||||
inline uint64_t id() const { return _id; }
|
||||
|
||||
/**
|
||||
* @return World definition timestamp
|
||||
*/
|
||||
inline uint64_t timestamp() const { return _ts; }
|
||||
|
||||
/**
|
||||
* @return C25519 signature
|
||||
*/
|
||||
inline const C25519::Signature &signature() const { return _signature; }
|
||||
|
||||
/**
|
||||
* @return Public key that must sign next update
|
||||
*/
|
||||
inline const C25519::Public &updatesMustBeSignedBy() const { return _updatesMustBeSignedBy; }
|
||||
|
||||
/**
|
||||
* Check whether a world update should replace this one
|
||||
*
|
||||
* @param update Candidate update
|
||||
* @return True if update is newer than current, matches its ID and type, and is properly signed (or if current is NULL)
|
||||
*/
|
||||
inline bool shouldBeReplacedBy(const World &update)
|
||||
{
|
||||
if ((_id == 0)||(_type == TYPE_NULL))
|
||||
return true;
|
||||
if ((_id == update._id)&&(_ts < update._ts)&&(_type == update._type)) {
|
||||
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
|
||||
update.serialize(tmp,true);
|
||||
return C25519::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if this World is non-empty
|
||||
*/
|
||||
inline operator bool() const { return (_type != TYPE_NULL); }
|
||||
|
||||
template<unsigned int C>
|
||||
inline void serialize(Buffer<C> &b,bool forSign = false) const
|
||||
{
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
|
||||
b.append((uint8_t)_type);
|
||||
b.append((uint64_t)_id);
|
||||
b.append((uint64_t)_ts);
|
||||
b.append(_updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
if (!forSign)
|
||||
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
|
||||
b.append((uint8_t)_roots.size());
|
||||
for(std::vector<Root>::const_iterator r(_roots.begin());r!=_roots.end();++r) {
|
||||
r->identity.serialize(b);
|
||||
b.append((uint8_t)r->stableEndpoints.size());
|
||||
for(std::vector<InetAddress>::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep)
|
||||
ep->serialize(b);
|
||||
}
|
||||
if (_type == TYPE_MOON)
|
||||
b.append((uint16_t)0); // no attached dictionary (for future use)
|
||||
|
||||
if (forSign) b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL);
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
|
||||
{
|
||||
unsigned int p = startAt;
|
||||
|
||||
_roots.clear();
|
||||
|
||||
switch((Type)b[p++]) {
|
||||
case TYPE_NULL: _type = TYPE_NULL; break; // shouldn't ever really happen in serialized data but it's not invalid
|
||||
case TYPE_PLANET: _type = TYPE_PLANET; break;
|
||||
case TYPE_MOON: _type = TYPE_MOON; break;
|
||||
default:
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
|
||||
}
|
||||
|
||||
_id = b.template at<uint64_t>(p); p += 8;
|
||||
_ts = b.template at<uint64_t>(p); p += 8;
|
||||
memcpy(_updatesMustBeSignedBy.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); p += ZT_C25519_PUBLIC_KEY_LEN;
|
||||
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
|
||||
const unsigned int numRoots = (unsigned int)b[p++];
|
||||
if (numRoots > ZT_WORLD_MAX_ROOTS)
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
|
||||
for(unsigned int k=0;k<numRoots;++k) {
|
||||
_roots.push_back(Root());
|
||||
Root &r = _roots.back();
|
||||
p += r.identity.deserialize(b,p);
|
||||
unsigned int numStableEndpoints = b[p++];
|
||||
if (numStableEndpoints > ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)
|
||||
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
|
||||
for(unsigned int kk=0;kk<numStableEndpoints;++kk) {
|
||||
r.stableEndpoints.push_back(InetAddress());
|
||||
p += r.stableEndpoints.back().deserialize(b,p);
|
||||
}
|
||||
}
|
||||
if (_type == TYPE_MOON)
|
||||
p += b.template at<uint16_t>(p) + 2;
|
||||
|
||||
return (p - startAt);
|
||||
}
|
||||
|
||||
inline bool operator==(const World &w) const { return ((_id == w._id)&&(_ts == w._ts)&&(memcmp(_updatesMustBeSignedBy.data,w._updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN) == 0)&&(memcmp(_signature.data,w._signature.data,ZT_C25519_SIGNATURE_LEN) == 0)&&(_roots == w._roots)&&(_type == w._type)); }
|
||||
inline bool operator!=(const World &w) const { return (!(*this == w)); }
|
||||
|
||||
/**
|
||||
* Create a World object signed with a key pair
|
||||
*
|
||||
* @param t World type
|
||||
* @param id World ID
|
||||
* @param ts World timestamp / revision
|
||||
* @param sk Key that must be used to sign the next future update to this world
|
||||
* @param roots Roots and their stable endpoints
|
||||
* @param signWith Key to sign this World with (can have the same public as the next-update signing key, but doesn't have to)
|
||||
* @return Signed World object
|
||||
*/
|
||||
static inline World make(World::Type t,uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector<World::Root> &roots,const C25519::Pair &signWith)
|
||||
{
|
||||
World w;
|
||||
w._id = id;
|
||||
w._ts = ts;
|
||||
w._type = t;
|
||||
w._updatesMustBeSignedBy = sk;
|
||||
w._roots = roots;
|
||||
|
||||
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
|
||||
w.serialize(tmp,true);
|
||||
w._signature = C25519::sign(signWith,tmp.data(),tmp.size());
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t _id;
|
||||
uint64_t _ts;
|
||||
Type _type;
|
||||
C25519::Public _updatesMustBeSignedBy;
|
||||
C25519::Signature _signature;
|
||||
std::vector<Root> _roots;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
177
one.cpp
177
one.cpp
@ -79,7 +79,6 @@
|
||||
#include "node/Utils.hpp"
|
||||
#include "node/NetworkController.hpp"
|
||||
#include "node/Buffer.hpp"
|
||||
#include "node/World.hpp"
|
||||
|
||||
#include "osdep/OSUtils.hpp"
|
||||
#include "osdep/Http.hpp"
|
||||
@ -136,9 +135,6 @@ static void cliPrintHelp(const char *pn,FILE *out)
|
||||
fprintf(out," leave <network> - Leave a network" ZT_EOL_S);
|
||||
fprintf(out," set <network> <setting> - Set a network setting" ZT_EOL_S);
|
||||
fprintf(out," get <network> <setting> - Get a network setting" ZT_EOL_S);
|
||||
fprintf(out," listmoons - List moons (federated root sets)" ZT_EOL_S);
|
||||
fprintf(out," orbit <world ID> <seed> - Join a moon via any member root" ZT_EOL_S);
|
||||
fprintf(out," deorbit <world ID> - Leave a moon" ZT_EOL_S);
|
||||
fprintf(out,ZT_EOL_S"Available settings:" ZT_EOL_S);
|
||||
fprintf(out," Settings to use with [get/set] may include property names from " ZT_EOL_S);
|
||||
fprintf(out," the JSON output of \"zerotier-cli -j listnetworks\". Additionally, " ZT_EOL_S);
|
||||
@ -593,80 +589,6 @@ static int cli(int argc,char **argv)
|
||||
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
|
||||
return 1;
|
||||
}
|
||||
} else if (command == "listmoons") {
|
||||
const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/moon",requestHeaders,responseHeaders,responseBody);
|
||||
|
||||
if (scode == 0) {
|
||||
printf("Error connecting to the ZeroTier service: %s\n\nPlease check that the service is running and that TCP port 9993 can be contacted via 127.0.0.1." ZT_EOL_S, responseBody.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
nlohmann::json j;
|
||||
try {
|
||||
j = OSUtils::jsonParse(responseBody);
|
||||
} catch (std::exception &exc) {
|
||||
printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what());
|
||||
return 1;
|
||||
} catch ( ... ) {
|
||||
printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (scode == 200) {
|
||||
printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str());
|
||||
return 0;
|
||||
} else {
|
||||
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
|
||||
return 1;
|
||||
}
|
||||
} else if (command == "orbit") {
|
||||
const uint64_t worldId = Utils::hexStrToU64(arg1.c_str());
|
||||
const uint64_t seed = Utils::hexStrToU64(arg2.c_str());
|
||||
if ((worldId)&&(seed)) {
|
||||
char jsons[1024];
|
||||
OSUtils::ztsnprintf(jsons,sizeof(jsons),"{\"seed\":\"%s\"}",arg2.c_str());
|
||||
char cl[128];
|
||||
OSUtils::ztsnprintf(cl,sizeof(cl),"%u",(unsigned int)strlen(jsons));
|
||||
requestHeaders["Content-Type"] = "application/json";
|
||||
requestHeaders["Content-Length"] = cl;
|
||||
unsigned int scode = Http::POST(
|
||||
1024 * 1024 * 16,
|
||||
60000,
|
||||
(const struct sockaddr *)&addr,
|
||||
(std::string("/moon/") + arg1).c_str(),
|
||||
requestHeaders,
|
||||
jsons,
|
||||
(unsigned long)strlen(jsons),
|
||||
responseHeaders,
|
||||
responseBody);
|
||||
if (scode == 200) {
|
||||
printf("200 orbit OK" ZT_EOL_S);
|
||||
return 0;
|
||||
} else {
|
||||
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else if (command == "deorbit") {
|
||||
unsigned int scode = Http::DEL(
|
||||
1024 * 1024 * 16,
|
||||
60000,
|
||||
(const struct sockaddr *)&addr,
|
||||
(std::string("/moon/") + arg1).c_str(),
|
||||
requestHeaders,
|
||||
responseHeaders,
|
||||
responseBody);
|
||||
if (scode == 200) {
|
||||
if (json) {
|
||||
printf("%s",cliFixJsonCRs(responseBody).c_str());
|
||||
} else {
|
||||
printf("200 deorbit OK" ZT_EOL_S);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
|
||||
return 1;
|
||||
}
|
||||
} else if (command == "set") {
|
||||
if (arg1.length() != 16) {
|
||||
fprintf(stderr,"invalid format: must be a 16-digit (network) ID\n");
|
||||
@ -829,8 +751,6 @@ static void idtoolPrintHelp(FILE *out,const char *pn)
|
||||
fprintf(out," getpublic <identity.secret>" ZT_EOL_S);
|
||||
fprintf(out," sign <identity.secret> <file>" ZT_EOL_S);
|
||||
fprintf(out," verify <identity.secret/public> <file> <signature>" ZT_EOL_S);
|
||||
fprintf(out," initmoon <identity.public of first seed>" ZT_EOL_S);
|
||||
fprintf(out," genmoon <moon json>" ZT_EOL_S);
|
||||
}
|
||||
|
||||
static Identity getIdFromArg(char *arg)
|
||||
@ -872,7 +792,7 @@ static int idtool(int argc,char **argv)
|
||||
|
||||
Identity id;
|
||||
for(;;) {
|
||||
id.generate();
|
||||
id.generate(Identity::C25519);
|
||||
if ((id.address().toInt() >> (40 - vanityBits)) == vanity) {
|
||||
if (vanityBits > 0) {
|
||||
fprintf(stderr,"vanity address: found %.10llx !\n",(unsigned long long)id.address().toInt());
|
||||
@ -950,9 +870,10 @@ static int idtool(int argc,char **argv)
|
||||
fprintf(stderr,"%s is not readable" ZT_EOL_S,argv[3]);
|
||||
return 1;
|
||||
}
|
||||
C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length());
|
||||
char hexbuf[1024];
|
||||
printf("%s",Utils::hex(signature.data,ZT_C25519_SIGNATURE_LEN,hexbuf));
|
||||
uint8_t signature[ZT_SIGNATURE_BUFFER_SIZE];
|
||||
const unsigned int siglen = id.sign(inf.data(),(unsigned int)inf.length(),signature,sizeof(signature));
|
||||
char hexbuf[256];
|
||||
printf("%s",Utils::hex(signature,siglen,hexbuf));
|
||||
} else if (!strcmp(argv[1],"verify")) {
|
||||
if (argc < 5) {
|
||||
idtoolPrintHelp(stdout,argv[0]);
|
||||
@ -990,94 +911,6 @@ static int idtool(int argc,char **argv)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(argv[1],"initmoon")) {
|
||||
if (argc < 3) {
|
||||
idtoolPrintHelp(stdout,argv[0]);
|
||||
} else {
|
||||
const Identity id = getIdFromArg(argv[2]);
|
||||
if (!id) {
|
||||
fprintf(stderr,"%s is not a valid identity" ZT_EOL_S,argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
C25519::Pair kp(C25519::generate());
|
||||
|
||||
char idtmp[4096];
|
||||
nlohmann::json mj;
|
||||
mj["objtype"] = "world";
|
||||
mj["worldType"] = "moon";
|
||||
mj["updatesMustBeSignedBy"] = mj["signingKey"] = Utils::hex(kp.pub.data,ZT_C25519_PUBLIC_KEY_LEN,idtmp);
|
||||
mj["signingKey_SECRET"] = Utils::hex(kp.priv.data,ZT_C25519_PRIVATE_KEY_LEN,idtmp);
|
||||
mj["id"] = id.address().toString(idtmp);
|
||||
nlohmann::json seedj;
|
||||
seedj["identity"] = id.toString(false,idtmp);
|
||||
seedj["stableEndpoints"] = nlohmann::json::array();
|
||||
(mj["roots"] = nlohmann::json::array()).push_back(seedj);
|
||||
std::string mjd(OSUtils::jsonDump(mj));
|
||||
|
||||
printf("%s" ZT_EOL_S,mjd.c_str());
|
||||
}
|
||||
} else if (!strcmp(argv[1],"genmoon")) {
|
||||
if (argc < 3) {
|
||||
idtoolPrintHelp(stdout,argv[0]);
|
||||
} else {
|
||||
std::string buf;
|
||||
if (!OSUtils::readFile(argv[2],buf)) {
|
||||
fprintf(stderr,"cannot read %s" ZT_EOL_S,argv[2]);
|
||||
return 1;
|
||||
}
|
||||
nlohmann::json mj(OSUtils::jsonParse(buf));
|
||||
|
||||
const uint64_t id = Utils::hexStrToU64(OSUtils::jsonString(mj["id"],"0").c_str());
|
||||
if (!id) {
|
||||
fprintf(stderr,"ID in %s is invalid" ZT_EOL_S,argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
World::Type t;
|
||||
if (mj["worldType"] == "moon") {
|
||||
t = World::TYPE_MOON;
|
||||
} else if (mj["worldType"] == "planet") {
|
||||
t = World::TYPE_PLANET;
|
||||
} else {
|
||||
fprintf(stderr,"invalid worldType" ZT_EOL_S);
|
||||
return 1;
|
||||
}
|
||||
|
||||
C25519::Pair signingKey;
|
||||
C25519::Public updatesMustBeSignedBy;
|
||||
Utils::unhex(OSUtils::jsonString(mj["signingKey"],"").c_str(),signingKey.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
Utils::unhex(OSUtils::jsonString(mj["signingKey_SECRET"],"").c_str(),signingKey.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
Utils::unhex(OSUtils::jsonString(mj["updatesMustBeSignedBy"],"").c_str(),updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
|
||||
std::vector<World::Root> roots;
|
||||
nlohmann::json &rootsj = mj["roots"];
|
||||
if (rootsj.is_array()) {
|
||||
for(unsigned long i=0;i<(unsigned long)rootsj.size();++i) {
|
||||
nlohmann::json &r = rootsj[i];
|
||||
if (r.is_object()) {
|
||||
roots.push_back(World::Root());
|
||||
roots.back().identity = Identity(OSUtils::jsonString(r["identity"],"").c_str());
|
||||
nlohmann::json &stableEndpointsj = r["stableEndpoints"];
|
||||
if (stableEndpointsj.is_array()) {
|
||||
for(unsigned long k=0;k<(unsigned long)stableEndpointsj.size();++k)
|
||||
roots.back().stableEndpoints.push_back(InetAddress(OSUtils::jsonString(stableEndpointsj[k],"").c_str()));
|
||||
std::sort(roots.back().stableEndpoints.begin(),roots.back().stableEndpoints.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::sort(roots.begin(),roots.end());
|
||||
|
||||
const int64_t now = OSUtils::now();
|
||||
World w(World::make(t,id,now,updatesMustBeSignedBy,roots,signingKey));
|
||||
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> wbuf;
|
||||
w.serialize(wbuf);
|
||||
char fn[128];
|
||||
OSUtils::ztsnprintf(fn,sizeof(fn),"%.16llx.moon",w.id());
|
||||
OSUtils::writeFile(fn,wbuf.data(),wbuf.size());
|
||||
printf("wrote %s (signed world with timestamp %llu)" ZT_EOL_S,fn,(unsigned long long)now);
|
||||
}
|
||||
} else {
|
||||
idtoolPrintHelp(stdout,argv[0]);
|
||||
return 1;
|
||||
|
20
selftest.cpp
20
selftest.cpp
@ -367,8 +367,8 @@ static int testCrypto()
|
||||
memcpy(p1.priv.data,C25519_TEST_VECTORS[k].priv1,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
memcpy(p2.pub.data,C25519_TEST_VECTORS[k].pub2,ZT_C25519_PUBLIC_KEY_LEN);
|
||||
memcpy(p2.priv.data,C25519_TEST_VECTORS[k].priv2,ZT_C25519_PRIVATE_KEY_LEN);
|
||||
C25519::agree(p1,p2.pub,buf1,64);
|
||||
C25519::agree(p2,p1.pub,buf2,64);
|
||||
C25519::agree(p1.priv,p2.pub,buf1,64);
|
||||
C25519::agree(p2.priv,p1.pub,buf2,64);
|
||||
if (memcmp(buf1,buf2,64)) {
|
||||
std::cout << "FAIL (1)" << std::endl;
|
||||
return -1;
|
||||
@ -398,9 +398,9 @@ static int testCrypto()
|
||||
C25519::Pair p1 = C25519::generate();
|
||||
C25519::Pair p2 = C25519::generate();
|
||||
C25519::Pair p3 = C25519::generate();
|
||||
C25519::agree(p1,p2.pub,buf1,64);
|
||||
C25519::agree(p2,p1.pub,buf2,64);
|
||||
C25519::agree(p3,p1.pub,buf3,64);
|
||||
C25519::agree(p1.priv,p2.pub,buf1,64);
|
||||
C25519::agree(p2.priv,p1.pub,buf2,64);
|
||||
C25519::agree(p3.priv,p1.pub,buf3,64);
|
||||
// p1<>p2 should equal p1<>p2
|
||||
if (memcmp(buf1,buf2,64)) {
|
||||
std::cout << "FAIL (1)" << std::endl;
|
||||
@ -420,7 +420,7 @@ static int testCrypto()
|
||||
bp[k] = C25519::generate();
|
||||
uint64_t st = OSUtils::now();
|
||||
for(unsigned int k=0;k<50;++k) {
|
||||
C25519::agree(bp[~k & 7],bp[k & 7].pub,buf1,64);
|
||||
C25519::agree(bp[~k & 7].priv,bp[k & 7].pub,buf1,64);
|
||||
}
|
||||
uint64_t et = OSUtils::now();
|
||||
std::cout << ((double)(et - st) / 50.0) << "ms per agreement." << std::endl;
|
||||
@ -508,7 +508,7 @@ static int testIdentity()
|
||||
for(unsigned int k=0;k<4;++k) {
|
||||
std::cout << "[identity] Generate identity... "; std::cout.flush();
|
||||
uint64_t genstart = OSUtils::now();
|
||||
id.generate();
|
||||
id.generate(Identity::C25519);
|
||||
uint64_t genend = OSUtils::now();
|
||||
std::cout << "(took " << (genend - genstart) << "ms): " << id.toString(true,buf2) << std::endl;
|
||||
std::cout << "[identity] Locally validate identity: ";
|
||||
@ -581,13 +581,13 @@ static int testCertificate()
|
||||
|
||||
Identity authority;
|
||||
std::cout << "[certificate] Generating identity to act as authority... "; std::cout.flush();
|
||||
authority.generate();
|
||||
authority.generate(Identity::C25519);
|
||||
std::cout << authority.address().toString(buf) << std::endl;
|
||||
|
||||
Identity idA,idB;
|
||||
std::cout << "[certificate] Generating identities A and B... "; std::cout.flush();
|
||||
idA.generate();
|
||||
idB.generate();
|
||||
idA.generate(Identity::C25519);
|
||||
idB.generate(Identity::C25519);
|
||||
std::cout << idA.address().toString(buf) << ", " << idB.address().toString(buf) << std::endl;
|
||||
|
||||
std::cout << "[certificate] Generating certificates A and B...";
|
||||
|
@ -48,7 +48,6 @@
|
||||
#include "../node/InetAddress.hpp"
|
||||
#include "../node/MAC.hpp"
|
||||
#include "../node/Identity.hpp"
|
||||
#include "../node/World.hpp"
|
||||
#include "../node/Salsa20.hpp"
|
||||
#include "../node/Poly1305.hpp"
|
||||
#include "../node/SHA512.hpp"
|
||||
@ -346,28 +345,6 @@ static void _peerAggregateLinkToJson(nlohmann::json &pj,const ZT_Peer *peer)
|
||||
pj["paths"] = pa;
|
||||
}
|
||||
|
||||
static void _moonToJson(nlohmann::json &mj,const World &world)
|
||||
{
|
||||
char tmp[4096];
|
||||
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",world.id());
|
||||
mj["id"] = tmp;
|
||||
mj["timestamp"] = world.timestamp();
|
||||
mj["signature"] = Utils::hex(world.signature().data,ZT_C25519_SIGNATURE_LEN,tmp);
|
||||
mj["updatesMustBeSignedBy"] = Utils::hex(world.updatesMustBeSignedBy().data,ZT_C25519_PUBLIC_KEY_LEN,tmp);
|
||||
nlohmann::json ra = nlohmann::json::array();
|
||||
for(std::vector<World::Root>::const_iterator r(world.roots().begin());r!=world.roots().end();++r) {
|
||||
nlohmann::json rj;
|
||||
rj["identity"] = r->identity.toString(false,tmp);
|
||||
nlohmann::json eps = nlohmann::json::array();
|
||||
for(std::vector<InetAddress>::const_iterator a(r->stableEndpoints.begin());a!=r->stableEndpoints.end();++a)
|
||||
eps.push_back(a->toString(tmp));
|
||||
rj["stableEndpoints"] = eps;
|
||||
ra.push_back(rj);
|
||||
}
|
||||
mj["roots"] = ra;
|
||||
mj["waiting"] = false;
|
||||
}
|
||||
|
||||
class OneServiceImpl;
|
||||
|
||||
static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf);
|
||||
@ -780,16 +757,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Orbit existing moons in moons.d
|
||||
{
|
||||
std::vector<std::string> moonsDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "moons.d").c_str()));
|
||||
for(std::vector<std::string>::iterator f(moonsDotD.begin());f!=moonsDotD.end();++f) {
|
||||
std::size_t dot = f->find_last_of('.');
|
||||
if ((dot == 16)&&(f->substr(16) == ".moon"))
|
||||
_node->orbit((void *)0,Utils::hexStrToU64(f->substr(0,dot).c_str()),0);
|
||||
}
|
||||
}
|
||||
|
||||
// Main I/O loop
|
||||
_nextBackgroundTaskDeadline = 0;
|
||||
int64_t clockShouldBe = OSUtils::now();
|
||||
@ -1287,37 +1254,8 @@ public:
|
||||
settings["softwareUpdate"] = OSUtils::jsonString(settings["softwareUpdate"],ZT_SOFTWARE_UPDATE_DEFAULT);
|
||||
settings["softwareUpdateChannel"] = OSUtils::jsonString(settings["softwareUpdateChannel"],ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL);
|
||||
#endif
|
||||
const World planet(_node->planet());
|
||||
res["planetWorldId"] = planet.id();
|
||||
res["planetWorldTimestamp"] = planet.timestamp();
|
||||
|
||||
scode = 200;
|
||||
} else if (ps[0] == "moon") {
|
||||
std::vector<World> moons(_node->moons());
|
||||
if (ps.size() == 1) {
|
||||
// Return [array] of all moons
|
||||
|
||||
res = json::array();
|
||||
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
|
||||
json mj;
|
||||
_moonToJson(mj,*m);
|
||||
res.push_back(mj);
|
||||
}
|
||||
|
||||
scode = 200;
|
||||
} else {
|
||||
// Return a single moon by ID
|
||||
|
||||
const uint64_t id = Utils::hexStrToU64(ps[1].c_str());
|
||||
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
|
||||
if (m->id() == id) {
|
||||
_moonToJson(res,*m);
|
||||
scode = 200;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else if (ps[0] == "network") {
|
||||
ZT_VirtualNetworkList *nws = _node->networks();
|
||||
if (nws) {
|
||||
@ -1390,44 +1328,7 @@ public:
|
||||
} else if ((httpMethod == HTTP_POST)||(httpMethod == HTTP_PUT)) {
|
||||
if (isAuth) {
|
||||
|
||||
if (ps[0] == "moon") {
|
||||
if (ps.size() == 2) {
|
||||
|
||||
uint64_t seed = 0;
|
||||
try {
|
||||
json j(OSUtils::jsonParse(body));
|
||||
if (j.is_object()) {
|
||||
seed = Utils::hexStrToU64(OSUtils::jsonString(j["seed"],"0").c_str());
|
||||
}
|
||||
} catch ( ... ) {
|
||||
// discard invalid JSON
|
||||
}
|
||||
|
||||
std::vector<World> moons(_node->moons());
|
||||
const uint64_t id = Utils::hexStrToU64(ps[1].c_str());
|
||||
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
|
||||
if (m->id() == id) {
|
||||
_moonToJson(res,*m);
|
||||
scode = 200;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((scode != 200)&&(seed != 0)) {
|
||||
char tmp[64];
|
||||
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",id);
|
||||
res["id"] = tmp;
|
||||
res["roots"] = json::array();
|
||||
res["timestamp"] = 0;
|
||||
res["signature"] = json();
|
||||
res["updatesMustBeSignedBy"] = json();
|
||||
res["waiting"] = true;
|
||||
_node->orbit((void *)0,id,seed);
|
||||
scode = 200;
|
||||
}
|
||||
|
||||
} else scode = 404;
|
||||
} else if (ps[0] == "network") {
|
||||
if (ps[0] == "network") {
|
||||
if (ps.size() == 2) {
|
||||
|
||||
uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str());
|
||||
@ -1474,13 +1375,7 @@ public:
|
||||
} else if (httpMethod == HTTP_DELETE) {
|
||||
if (isAuth) {
|
||||
|
||||
if (ps[0] == "moon") {
|
||||
if (ps.size() == 2) {
|
||||
_node->deorbit((void *)0,Utils::hexStrToU64(ps[1].c_str()));
|
||||
res["result"] = true;
|
||||
scode = 200;
|
||||
} // else 404
|
||||
} else if (ps[0] == "network") {
|
||||
if (ps[0] == "network") {
|
||||
ZT_VirtualNetworkList *nws = _node->networks();
|
||||
if (nws) {
|
||||
if (ps.size() == 2) {
|
||||
@ -2370,13 +2265,6 @@ public:
|
||||
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str());
|
||||
secure = true;
|
||||
break;
|
||||
case ZT_STATE_OBJECT_PLANET:
|
||||
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str());
|
||||
break;
|
||||
case ZT_STATE_OBJECT_MOON:
|
||||
OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "moons.d",_homePath.c_str());
|
||||
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.moon",dirname,(unsigned long long)id[0]);
|
||||
break;
|
||||
case ZT_STATE_OBJECT_NETWORK_CONFIG:
|
||||
OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str());
|
||||
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]);
|
||||
@ -2522,12 +2410,6 @@ public:
|
||||
case ZT_STATE_OBJECT_IDENTITY_SECRET:
|
||||
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str());
|
||||
break;
|
||||
case ZT_STATE_OBJECT_PLANET:
|
||||
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str());
|
||||
break;
|
||||
case ZT_STATE_OBJECT_MOON:
|
||||
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d" ZT_PATH_SEPARATOR_S "%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]);
|
||||
break;
|
||||
case ZT_STATE_OBJECT_NETWORK_CONFIG:
|
||||
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]);
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user