Replace piecemeal designation of upstreams with the concept of moons, which is simpler and easier to use and inherits all the cool live update stuff of worlds (now called planets) and global roots.

This commit is contained in:
Adam Ierymenko 2017-01-27 13:27:52 -08:00
parent b88f573733
commit 64774d0d4f
12 changed files with 242 additions and 296 deletions

View file

@ -48,16 +48,6 @@
*/
#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 indicating null / empty World object
*/
#define ZT_WORLD_ID_NULL 0
/**
* World ID for a test network with ephemeral or temporary roots
*/
#define ZT_WORLD_ID_TESTNET 1
/**
* World ID for Earth
*
@ -90,15 +80,23 @@ namespace ZeroTier {
* 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.
*
* If you absolutely must run your own "unofficial" ZeroTier network, please
* define your world IDs above 0xffffffff (4294967295). Code to make a World
* is in mkworld.cpp in the parent directory and must be edited to change
* settings.
*/
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;
@ -113,45 +111,44 @@ public:
* Construct an empty / null World
*/
World() :
_id(ZT_WORLD_ID_NULL),
_ts(0) {}
_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 throw() { return _roots; }
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 throw() { return _id; }
inline uint64_t id() const { return _id; }
/**
* @return World definition timestamp
*/
inline uint64_t timestamp() const throw() { return _ts; }
inline uint64_t timestamp() const { return _ts; }
/**
* Check whether a world update should replace this one
*
* A new world update is valid if it is for the same world ID, is newer,
* and is signed by the current world's signing key. If this world object
* is null, it can always be updated.
*
* @param update Candidate update
* @param fullSignatureCheck Perform full cryptographic signature check (true == yes, false == skip)
* @return True if update is newer than current and is properly signed
* @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,bool fullSignatureCheck)
inline bool shouldBeReplacedBy(const World &update)
{
if (_id == ZT_WORLD_ID_NULL)
if ((_id == 0)||(_type == TYPE_NULL))
return true;
if ((_id == update._id)&&(_ts < update._ts)) {
if (fullSignatureCheck) {
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
update.serialize(tmp,true);
return C25519::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature);
} else 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;
}
@ -159,14 +156,14 @@ public:
/**
* @return True if this World is non-empty
*/
inline operator bool() const throw() { return (_id != ZT_WORLD_ID_NULL); }
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)0x01);
b.append((uint8_t)_type);
b.append((uint64_t)_id);
b.append((uint64_t)_ts);
b.append(_updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN);
@ -190,14 +187,19 @@ public:
_roots.clear();
if (b[p++] != 0x01)
throw std::invalid_argument("invalid object type");
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 std::invalid_argument("invalid world 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;
unsigned int numRoots = b[p++];
const unsigned int numRoots = (unsigned int)b[p++];
if (numRoots > ZT_WORLD_MAX_ROOTS)
throw std::invalid_argument("too many roots in World");
for(unsigned int k=0;k<numRoots;++k) {
@ -216,12 +218,15 @@ public:
return (p - startAt);
}
inline bool operator==(const World &w) const throw() { return ((_id == w._id)&&(_ts == w._ts)&&(_updatesMustBeSignedBy == w._updatesMustBeSignedBy)&&(_signature == w._signature)&&(_roots == w._roots)); }
inline bool operator!=(const World &w) const throw() { return (!(*this == w)); }
inline bool operator==(const World &w) const { return ((_id == w._id)&&(_ts == w._ts)&&(_updatesMustBeSignedBy == w._updatesMustBeSignedBy)&&(_signature == w._signature)&&(_roots == w._roots)&&(_type == w._type)); }
inline bool operator!=(const World &w) const { return (!(*this == w)); }
inline bool operator<(const World &w) const { return (((int)_type < (int)w._type) ? true : ((_type == w._type) ? (_id < w._id) : false)); }
protected:
uint64_t _id;
uint64_t _ts;
Type _type;
C25519::Public _updatesMustBeSignedBy;
C25519::Signature _signature;
std::vector<Root> _roots;