Simplify root API

This commit is contained in:
Adam Ierymenko 2019-09-26 13:35:56 -07:00
parent 7061f13b24
commit 3b3e6d2bfc
No known key found for this signature in database
GPG Key ID: C8877CF2D7A5D7F3
8 changed files with 149 additions and 299 deletions

View File

@ -355,6 +355,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
if req.Method == http.MethodPost || req.Method == http.MethodPut { if req.Method == http.MethodPost || req.Method == http.MethodPut {
if queriedID == 0 { if queriedID == 0 {
apiSendObj(out, req, http.StatusBadRequest, nil) apiSendObj(out, req, http.StatusBadRequest, nil)
} else {
} }
} else if req.Method == http.MethodGet || req.Method == http.MethodHead { } else if req.Method == http.MethodGet || req.Method == http.MethodHead {
roots := node.Roots() roots := node.Roots()

View File

@ -624,12 +624,18 @@ func (n *Node) Peers() []*Peer {
p2.Version = [3]int{int(p.versionMajor), int(p.versionMinor), int(p.versionRev)} p2.Version = [3]int{int(p.versionMajor), int(p.versionMinor), int(p.versionRev)}
p2.Latency = int(p.latency) p2.Latency = int(p.latency)
p2.Role = int(p.role) p2.Role = int(p.role)
p2.Paths = make([]Path, 0, int(p.pathCount)) p2.Paths = make([]Path, 0, int(p.pathCount))
usingAllocation := false
for j := uintptr(0); j < uintptr(p.pathCount); j++ { for j := uintptr(0); j < uintptr(p.pathCount); j++ {
pt := &p.paths[j] pt := &p.paths[j]
if pt.alive != 0 { if pt.alive != 0 {
a := sockaddrStorageToUDPAddr(&pt.address) a := sockaddrStorageToUDPAddr(&pt.address)
if a != nil { if a != nil {
alloc := float32(pt.allocation)
if alloc > 0.0 {
usingAllocation = true
}
p2.Paths = append(p2.Paths, Path{ p2.Paths = append(p2.Paths, Path{
IP: a.IP, IP: a.IP,
Port: a.Port, Port: a.Port,
@ -644,18 +650,44 @@ func (n *Node) Peers() []*Peer {
Stability: float32(pt.stability), Stability: float32(pt.stability),
Throughput: uint64(pt.throughput), Throughput: uint64(pt.throughput),
MaxThroughput: uint64(pt.maxThroughput), MaxThroughput: uint64(pt.maxThroughput),
Allocation: float32(pt.allocation), Allocation: alloc,
}) })
} }
} }
} }
sort.Slice(p2.Paths, func(a, b int) bool { return p2.Paths[a].LastReceive < p2.Paths[b].LastReceive }) if !usingAllocation { // if all allocations are zero fall back to single path mode that uses the preferred flag
for i, j := 0, uintptr(0); j < uintptr(p.pathCount); j++ {
pt := &p.paths[j]
if pt.alive != 0 {
if pt.preferred == 0 {
p2.Paths[i].Allocation = 0.0
} else {
p2.Paths[i].Allocation = 1.0
}
i++
}
}
}
sort.Slice(p2.Paths, func(a, b int) bool {
pa := &p2.Paths[a]
pb := &p2.Paths[b]
if pb.Allocation < pa.Allocation { // invert order, put highest allocation paths first
return true
}
if pa.Allocation == pb.Allocation {
return pa.LastReceive < pb.LastReceive // then sort by most recent activity
}
return false
})
p2.Clock = TimeMs() p2.Clock = TimeMs()
peers = append(peers, p2) peers = append(peers, p2)
} }
C.ZT_Node_freeQueryResult(unsafe.Pointer(n.zn), unsafe.Pointer(pl)) C.ZT_Node_freeQueryResult(unsafe.Pointer(n.zn), unsafe.Pointer(pl))
} }
sort.Slice(peers, func(a, b int) bool { return peers[a].Address < peers[b].Address }) sort.Slice(peers, func(a, b int) bool {
return peers[a].Address < peers[b].Address
})
return peers return peers
} }

View File

@ -18,9 +18,13 @@ type Root struct {
DNSName string DNSName string
Identity *Identity Identity *Identity
Addresses []InetAddress Addresses []InetAddress
Locator []byte
Preferred bool Preferred bool
Online bool Online bool
} }
// Static returns true if this is a static root // Static returns true if this is a static root
func (r *Root) Static() bool { return len(r.DNSName) == 0 } func (r *Root) Static() bool { return len(r.DNSName) == 0 }
// Dynamic returns true if this is a dynamic root
func (r *Root) Dynamic() bool { return len(r.DNSName) > 0 }

View File

@ -1887,47 +1887,27 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_
ZT_SDK_API ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now); ZT_SDK_API ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now);
/** /**
* Set a static root * Add or update a root
*
* @param node Node instance
* @param identity Public identity of static root
* @param addresses Physical address(es) of root
* @param addressCount Number of physical addresses
* @return OK (0) or error code
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_setStaticRoot(ZT_Node *node,const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount);
/**
* Set a dynamic root
* *
* The node will begin trying to resolve the DNS TXT record for * The node will begin trying to resolve the DNS TXT record for
* this root and possibly obtain it from other peers. * this root and possibly obtain it from other peers.
* *
* @param node Node instance * @param node Node instance
* @param dnsName DNS name whose TXT record(s) contain the latest Locator for this root * @param name DNS name or simply the address in hex form for static roots
* @param defaultLocator Binary-serialized default locator of NULL if none (used if TXT records are not retrievable) * @param locator Binary-serialized locator of NULL if none
* @param defaultLocatorSize Size of default locator or 0 if none * @param locatorSize Size of locator or 0 if none
* @return OK (0) or error code * @return OK (0) or error code
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_setDynamicRoot(ZT_Node *node,const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize); ZT_SDK_API enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *locator,unsigned int locatorSize);
/**
* Remove a static root
*
* @param node Node instance
* @param identity Public identity of this root
* @return OK (0) or error code
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_removeStaticRoot(ZT_Node *node,const char *identity);
/** /**
* Remove a dynamic root * Remove a dynamic root
* *
* @param node Node instance * @param node Node instance
* @param dnsName DNS name of this dynamic root * @param name DNS name of this dynamic root or the address in hex form for static roots
* @return OK (0) or error code * @return OK (0) or error code
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_removeDynamicRoot(ZT_Node *node,const char *dnsName); ZT_SDK_API enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *name);
/** /**
* Get this node's 40-bit ZeroTier address * Get this node's 40-bit ZeroTier address

View File

@ -26,6 +26,7 @@
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
// These are absolute maximums -- real locators are never this big
#define ZT_LOCATOR_MAX_PHYSICAL_ADDRESSES 255 #define ZT_LOCATOR_MAX_PHYSICAL_ADDRESSES 255
#define ZT_LOCATOR_MAX_VIRTUAL_ADDRESSES 255 #define ZT_LOCATOR_MAX_VIRTUAL_ADDRESSES 255
@ -38,19 +39,15 @@ namespace ZeroTier {
* may be found. It can contain static physical addresses or virtual ZeroTier * may be found. It can contain static physical addresses or virtual ZeroTier
* addresses of nodes that can forward to the target node. Locator records * addresses of nodes that can forward to the target node. Locator records
* can be stored in signed DNS TXT record sets, in LF by roots, in caches, * can be stored in signed DNS TXT record sets, in LF by roots, in caches,
* etc. Version 2.x nodes can sign their own locators. Roots can create * etc.
* signed locators using their own signature for version 1.x nodes. Locators
* signed by the node whose location they describe always take precedence
* over locators signed by other nodes.
*/ */
class Locator class Locator
{ {
public: public:
ZT_ALWAYS_INLINE Locator() : _ts(0),_signatureLength(0) {} ZT_ALWAYS_INLINE Locator() : _ts(0),_signatureLength(0) {}
ZT_ALWAYS_INLINE const Identity &id() const { return _id; }
ZT_ALWAYS_INLINE const Identity &signer() const { return ((_signedBy) ? _signedBy : _id); }
ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; } ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
ZT_ALWAYS_INLINE const Identity &id() const { return _id; }
ZT_ALWAYS_INLINE const std::vector<InetAddress> &phy() const { return _physical; } ZT_ALWAYS_INLINE const std::vector<InetAddress> &phy() const { return _physical; }
ZT_ALWAYS_INLINE const std::vector<Identity> &virt() const { return _virtual; } ZT_ALWAYS_INLINE const std::vector<Identity> &virt() const { return _virtual; }
@ -76,11 +73,11 @@ public:
/** /**
* Method to be called after add() is called for each address or forwarding node * Method to be called after add() is called for each address or forwarding node
* *
* This sets timestamp and ID information and sorts and deduplicates target * @param id Identity that this locator describes (must contain private key)
* lists but does not sign the locator. The sign() method should be used after * @param ts Current time
* finish(). * @return True if completion and signature were successful
*/ */
ZT_ALWAYS_INLINE void finish(const Identity &id,const int64_t ts) ZT_ALWAYS_INLINE bool finish(const Identity &id,const int64_t ts)
{ {
_ts = ts; _ts = ts;
_id = id; _id = id;
@ -88,24 +85,10 @@ public:
_physical.erase(std::unique(_physical.begin(),_physical.end()),_physical.end()); _physical.erase(std::unique(_physical.begin(),_physical.end()),_physical.end());
std::sort(_virtual.begin(),_virtual.end()); std::sort(_virtual.begin(),_virtual.end());
_virtual.erase(std::unique(_virtual.begin(),_virtual.end()),_virtual.end()); _virtual.erase(std::unique(_virtual.begin(),_virtual.end()),_virtual.end());
}
/**
* Sign this locator (must be called after finish())
*/
ZT_ALWAYS_INLINE bool sign(const Identity &signingId)
{
if (!signingId.hasPrivate())
return false;
if (signingId == _id) {
_signedBy.zero();
} else {
_signedBy = signingId;
}
try { try {
ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>()); ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
serialize(*tmp,true); serialize(*tmp,true);
_signatureLength = signingId.sign(tmp->data(),tmp->size(),_signature,ZT_SIGNATURE_BUFFER_SIZE); _signatureLength = id.sign(tmp->data(),tmp->size(),_signature,ZT_SIGNATURE_BUFFER_SIZE);
return (_signatureLength > 0); return (_signatureLength > 0);
} catch ( ... ) { } catch ( ... ) {
return false; return false;
@ -122,8 +105,7 @@ public:
try { try {
ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>()); ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
serialize(*tmp,true); serialize(*tmp,true);
const bool ok = (_signedBy) ? _signedBy.verify(tmp->data(),tmp->size(),_signature,_signatureLength) : _id.verify(tmp->data(),tmp->size(),_signature,_signatureLength); return _id.verify(tmp->data(),tmp->size(),_signature,_signatureLength);
return ok;
} catch ( ... ) { } catch ( ... ) {
return false; return false;
} }
@ -155,6 +137,8 @@ public:
} }
/** /**
* This searches for an extracts a public key from a DNS name, if one is present.
*
* @return True if a key was found and successfully decoded * @return True if a key was found and successfully decoded
*/ */
static inline bool decodeSecureDnsName(const char *name,uint8_t p384SigningKeyPublic[ZT_ECC384_PUBLIC_KEY_SIZE]) static inline bool decodeSecureDnsName(const char *name,uint8_t p384SigningKeyPublic[ZT_ECC384_PUBLIC_KEY_SIZE])
@ -210,8 +194,9 @@ public:
ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>()); ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
serialize(*tmp,false); serialize(*tmp,false);
SHA384(s384,tmp->data(),tmp->size()); SHA384(s384,tmp->data(),tmp->size());
ECC384ECDSASign(p384SigningKeyPrivate,s384,((uint8_t *)tmp->unsafeData()) + tmp->size()); const unsigned int sigLocation = tmp->size();
tmp->addSize(ZT_ECC384_SIGNATURE_SIZE); tmp->addSize(ZT_ECC384_SIGNATURE_SIZE);
ECC384ECDSASign(p384SigningKeyPrivate,s384,((uint8_t *)tmp->unsafeData()) + sigLocation);
// Blob must be broken into multiple TXT records that must remain sortable so they are prefixed by a hex value. // Blob must be broken into multiple TXT records that must remain sortable so they are prefixed by a hex value.
// 186-byte chunks yield 248-byte base64 chunks which leaves some margin below the limit of 255. // 186-byte chunks yield 248-byte base64 chunks which leaves some margin below the limit of 255.
@ -292,12 +277,6 @@ public:
b.append((uint8_t)0); // version/flags, currently 0 b.append((uint8_t)0); // version/flags, currently 0
b.append((uint64_t)_ts); b.append((uint64_t)_ts);
_id.serialize(b,false); _id.serialize(b,false);
if (_signedBy) {
b.append((uint8_t)1); // number of signers, current max is 1
_signedBy.serialize(b,false); // be sure not to include private key!
} else {
b.append((uint8_t)0); // signer is _id
}
b.append((uint8_t)_physical.size()); b.append((uint8_t)_physical.size());
for(std::vector<InetAddress>::const_iterator i(_physical.begin());i!=_physical.end();++i) for(std::vector<InetAddress>::const_iterator i(_physical.begin());i!=_physical.end();++i)
i->serialize(b); i->serialize(b);
@ -354,16 +333,25 @@ public:
ZT_ALWAYS_INLINE bool addressesEqual(const Locator &l) const { return ((_physical == l._physical)&&(_virtual == l._virtual)); } ZT_ALWAYS_INLINE bool addressesEqual(const Locator &l) const { return ((_physical == l._physical)&&(_virtual == l._virtual)); }
ZT_ALWAYS_INLINE bool operator==(const Locator &l) const { return ((_ts == l._ts)&&(_id == l._id)&&(_signedBy == l._signedBy)&&(_physical == l._physical)&&(_virtual == l._virtual)&&(_signatureLength == l._signatureLength)&&(memcmp(_signature,l._signature,_signatureLength) == 0)); } ZT_ALWAYS_INLINE bool operator==(const Locator &l) const
{
return (
(_ts == l._ts)&&
(_id == l._id)&&
(_physical == l._physical)&&
(_virtual == l._virtual)&&
(_signatureLength == l._signatureLength)&&
(memcmp(_signature,l._signature,_signatureLength) == 0));
}
ZT_ALWAYS_INLINE bool operator!=(const Locator &l) const { return (!(*this == l)); } ZT_ALWAYS_INLINE bool operator!=(const Locator &l) const { return (!(*this == l)); }
ZT_ALWAYS_INLINE bool operator<(const Locator &l) const ZT_ALWAYS_INLINE bool operator<(const Locator &l) const
{ {
if (_id < l._id) return true; if (_ts < l._ts) return true; else if (_ts > l._ts) return false;
if (_ts < l._ts) return true; if (_id < l._id) return true; else if (_id > l._id) return false;
if (_signedBy < l._signedBy) return true; if (_physical < l._physical) return true; else if (_physical > l._physical) return false;
if (_physical < l._physical) return true; if (_virtual < l._virtual) return true; else if (_virtual > l._virtual) return false;
if (_virtual < l._virtual) return true; if (_signatureLength < l._signatureLength) return true;
return false; return (_signatureLength == l._signatureLength) ? (memcmp(_signature,l._signature,_signatureLength) < 0) : false;
} }
ZT_ALWAYS_INLINE bool operator>(const Locator &l) const { return (l < *this); } ZT_ALWAYS_INLINE bool operator>(const Locator &l) const { return (l < *this); }
ZT_ALWAYS_INLINE bool operator<=(const Locator &l) const { return (!(l < *this)); } ZT_ALWAYS_INLINE bool operator<=(const Locator &l) const { return (!(l < *this)); }
@ -374,7 +362,6 @@ public:
private: private:
int64_t _ts; int64_t _ts;
Identity _id; Identity _id;
Identity _signedBy; // signed by _id if nil/zero
std::vector<InetAddress> _physical; std::vector<InetAddress> _physical;
std::vector<Identity> _virtual; std::vector<Identity> _virtual;
unsigned int _signatureLength; unsigned int _signatureLength;

View File

@ -170,7 +170,9 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
if (nw) { if (nw) {
RR->sw->onLocalEthernet(tptr,nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength); RR->sw->onLocalEthernet(tptr,nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength);
return ZT_RESULT_OK; return ZT_RESULT_OK;
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } else {
return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
} }
// This is passed as the argument to the DNS request handler and // This is passed as the argument to the DNS request handler and
@ -184,7 +186,7 @@ struct _processBackgroundTasks_dnsResultAccumulator
static const ZT_DNSRecordType s_txtRecordType[1] = { ZT_DNS_RECORD_TXT }; static const ZT_DNSRecordType s_txtRecordType[1] = { ZT_DNS_RECORD_TXT };
struct _processBackgroundTasks_check_dynamicRoots struct _processBackgroundTasks_eachRootName
{ {
ZT_Node_Callbacks *cb; ZT_Node_Callbacks *cb;
Node *n; Node *n;
@ -194,7 +196,7 @@ struct _processBackgroundTasks_check_dynamicRoots
ZT_ALWAYS_INLINE bool operator()(const Str &dnsName,const Locator &loc) ZT_ALWAYS_INLINE bool operator()(const Str &dnsName,const Locator &loc)
{ {
if ((updateAll)||(!loc)) { if ((strchr(dnsName.c_str(),'.'))&&((updateAll)||(!loc))) {
_processBackgroundTasks_dnsResultAccumulator *dnsReq = new _processBackgroundTasks_dnsResultAccumulator(dnsName); _processBackgroundTasks_dnsResultAccumulator *dnsReq = new _processBackgroundTasks_dnsResultAccumulator(dnsName);
cb->dnsResolver(reinterpret_cast<ZT_Node *>(n),uPtr,tPtr,s_txtRecordType,1,dnsName.c_str(),(uintptr_t)dnsReq); cb->dnsResolver(reinterpret_cast<ZT_Node *>(n),uPtr,tPtr,s_txtRecordType,1,dnsName.c_str(),(uintptr_t)dnsReq);
} }
@ -258,7 +260,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
try { try {
// Periodically refresh locators for dynamic roots from their DNS names. // Periodically refresh locators for dynamic roots from their DNS names.
if (_cb.dnsResolver) { if (_cb.dnsResolver) {
_processBackgroundTasks_check_dynamicRoots cr; _processBackgroundTasks_eachRootName cr;
cr.cb = &_cb; cr.cb = &_cb;
cr.n = this; cr.n = this;
cr.uPtr = _uPtr; cr.uPtr = _uPtr;
@ -269,7 +271,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
} else { } else {
cr.updateAll = false; cr.updateAll = false;
} }
RR->topology->eachDynamicRoot(cr); RR->topology->eachRootName(cr);
} }
// Ping each root explicitly no matter what // Ping each root explicitly no matter what
@ -363,7 +365,7 @@ void Node::processDNSResult(
} else if (recordType == ZT_DNS_RECORD__END_OF_RESULTS) { } else if (recordType == ZT_DNS_RECORD__END_OF_RESULTS) {
Locator loc; Locator loc;
if (loc.decodeTxtRecords(acc->dnsName,acc->txtRecords.begin(),acc->txtRecords.end())) { if (loc.decodeTxtRecords(acc->dnsName,acc->txtRecords.begin(),acc->txtRecords.end())) {
RR->topology->setDynamicRoot(acc->dnsName,loc); RR->topology->setRoot(acc->dnsName,loc);
delete acc; delete acc;
} }
} }
@ -434,59 +436,38 @@ ZT_RootList *Node::listRoots(int64_t now)
return RR->topology->apiRoots(now); return RR->topology->apiRoots(now);
} }
enum ZT_ResultCode Node::setStaticRoot(const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount) enum ZT_ResultCode Node::setRoot(const char *name,const void *locator,unsigned int locatorSize)
{ {
if (!identity)
return ZT_RESULT_ERROR_BAD_PARAMETER;
Identity id;
if (id.fromString(identity)) {
if (id) {
std::vector<InetAddress> addrs;
for(unsigned int i=0;i<addressCount;++i)
addrs.push_back(InetAddress(addresses[i]));
RR->topology->setStaticRoot(identity,addrs);
return ZT_RESULT_OK;
}
}
return ZT_RESULT_ERROR_BAD_PARAMETER;
}
enum ZT_ResultCode Node::setDynamicRoot(const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize)
{
if (!dnsName)
return ZT_RESULT_ERROR_BAD_PARAMETER;
if (strlen(dnsName) >= 256)
return ZT_RESULT_ERROR_BAD_PARAMETER;
try { try {
Locator loc; Locator loc;
if ((defaultLocator)&&(defaultLocatorSize > 0)&&(defaultLocatorSize < 65535)) { if ((locator)&&(locatorSize > 0)&&(locatorSize < 65535)) {
ScopedPtr< Buffer<65536> > locbuf(new Buffer<65536>()); ScopedPtr< Buffer<65536> > locbuf(new Buffer<65536>());
locbuf->append(defaultLocator,defaultLocatorSize); locbuf->append(locator,locatorSize);
loc.deserialize(*locbuf,0); loc.deserialize(*locbuf,0);
if (!loc.verify()) if (!loc.verify())
loc = Locator(); return ZT_RESULT_ERROR_BAD_PARAMETER;
} }
return RR->topology->setDynamicRoot(Str(dnsName),loc) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; Str n;
if ((!name)||(strlen(name) == 0)) {
if (!loc)
return ZT_RESULT_ERROR_BAD_PARAMETER; /* no name and no locator */
char tmp[16];
loc.id().address().toString(tmp);
n = tmp;
} else {
n = name;
}
return RR->topology->setRoot(n,loc) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED;
} catch ( ... ) { } catch ( ... ) {
return ZT_RESULT_ERROR_BAD_PARAMETER; return ZT_RESULT_ERROR_BAD_PARAMETER;
} }
} }
enum ZT_ResultCode Node::removeStaticRoot(const char *identity) enum ZT_ResultCode Node::removeRoot(const char *name)
{
if (identity) {
Identity id;
if (id.fromString(identity))
RR->topology->removeStaticRoot(id);
}
return ZT_RESULT_OK;
}
enum ZT_ResultCode Node::removeDynamicRoot(const char *dnsName)
{ {
try { try {
if (dnsName) if (name)
RR->topology->removeDynamicRoot(Str(dnsName)); RR->topology->removeRoot(Str(name));
} catch ( ... ) {} } catch ( ... ) {}
return ZT_RESULT_OK; return ZT_RESULT_OK;
} }
@ -937,10 +918,10 @@ ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now)
} }
} }
enum ZT_ResultCode ZT_Node_setStaticRoot(ZT_Node *node,const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount) enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *locator,unsigned int locatorSize)
{ {
try { try {
return reinterpret_cast<ZeroTier::Node *>(node)->setStaticRoot(identity,addresses,addressCount); return reinterpret_cast<ZeroTier::Node *>(node)->setRoot(name,locator,locatorSize);
} catch (std::bad_alloc &exc) { } catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) { } catch ( ... ) {
@ -948,32 +929,10 @@ enum ZT_ResultCode ZT_Node_setStaticRoot(ZT_Node *node,const char *identity,cons
} }
} }
enum ZT_ResultCode ZT_Node_setDynamicRoot(ZT_Node *node,const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize) enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *name)
{ {
try { try {
return reinterpret_cast<ZeroTier::Node *>(node)->setDynamicRoot(dnsName,defaultLocator,defaultLocatorSize); return reinterpret_cast<ZeroTier::Node *>(node)->removeRoot(name);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_removeStaticRoot(ZT_Node *node,const char *identity)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->removeStaticRoot(identity);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_removeDynamicRoot(ZT_Node *node,const char *dnsName)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->removeDynamicRoot(dnsName);
} catch (std::bad_alloc &exc) { } catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) { } catch ( ... ) {

View File

@ -93,10 +93,8 @@ public:
ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); 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 multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_RootList *listRoots(int64_t now); ZT_RootList *listRoots(int64_t now);
enum ZT_ResultCode setStaticRoot(const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount); enum ZT_ResultCode setRoot(const char *name,const void *locator,unsigned int locatorSize);
enum ZT_ResultCode setDynamicRoot(const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize); enum ZT_ResultCode removeRoot(const char *name);
enum ZT_ResultCode removeStaticRoot(const char *identity);
enum ZT_ResultCode removeDynamicRoot(const char *dnsName);
uint64_t address() const; uint64_t address() const;
void status(ZT_NodeStatus *status) const; void status(ZT_NodeStatus *status) const;
ZT_PeerList *peers() const; ZT_PeerList *peers() const;

View File

@ -66,14 +66,14 @@ private:
ZT_ALWAYS_INLINE void _updateDynamicRootIdentities() ZT_ALWAYS_INLINE void _updateDynamicRootIdentities()
{ {
// assumes _dynamicRoots_l is locked // assumes _roots_l is locked
_dynamicRootIdentities.clear(); _rootIdentities.clear();
Hashtable< Str,Locator >::Iterator i(_dynamicRoots); Hashtable< Str,Locator >::Iterator i(_roots);
Str *k = (Str *)0; Str *k = (Str *)0;
Locator *v = (Locator *)0; Locator *v = (Locator *)0;
while (i.next(k,v)) { while (i.next(k,v)) {
if (*v) if (*v)
_dynamicRootIdentities.set(v->id(),true); _rootIdentities.set(v->id(),true);
} }
} }
@ -81,6 +81,10 @@ public:
ZT_ALWAYS_INLINE Topology(const RuntimeEnvironment *renv,const Identity &myId) : ZT_ALWAYS_INLINE Topology(const RuntimeEnvironment *renv,const Identity &myId) :
RR(renv), RR(renv),
_myIdentity(myId), _myIdentity(myId),
_peers(64),
_paths(128),
_roots(8),
_rootIdentities(8),
_numConfiguredPhysicalPaths(0), _numConfiguredPhysicalPaths(0),
_lastUpdatedBestRoot(0) {} _lastUpdatedBestRoot(0) {}
ZT_ALWAYS_INLINE ~Topology() {} ZT_ALWAYS_INLINE ~Topology() {}
@ -166,17 +170,8 @@ public:
*/ */
ZT_ALWAYS_INLINE bool isRoot(const Identity &id) const ZT_ALWAYS_INLINE bool isRoot(const Identity &id) const
{ {
{ Mutex::Lock l(_roots_l);
Mutex::Lock l(_dynamicRoots_l); return _rootIdentities.contains(id);
if (_dynamicRootIdentities.contains(id))
return true;
}
{
Mutex::Lock l(_staticRoots_l);
if (_staticRoots.contains(id))
return true;
}
return false;
} }
/** /**
@ -260,57 +255,28 @@ public:
template<typename F> template<typename F>
ZT_ALWAYS_INLINE void eachRoot(F f) ZT_ALWAYS_INLINE void eachRoot(F f)
{ {
{ Mutex::Lock l(_roots_l);
Mutex::Lock l(_dynamicRoots_l); Hashtable< Str,Locator >::Iterator i(_roots);
Hashtable< Str,Locator >::Iterator i(_dynamicRoots); Str *k = (Str *)0;
Str *k = (Str *)0; Locator *v = (Locator *)0;
Locator *v = (Locator *)0; while (i.next(k,v)) {
while (i.next(k,v)) { if (*v) {
if (*v) { for(std::vector<Identity>::const_iterator id(v->virt().begin());id!=v->virt().end();++id) {
for(std::vector<Identity>::const_iterator id(v->virt().begin());id!=v->virt().end();++id) {
const SharedPtr<Peer> *ap;
{
Mutex::Lock l2(_peers_l);
ap = _peers.get(id->address());
}
if (ap) {
if (!f(*ap,v->phy()))
return;
} else {
SharedPtr<Peer> p(new Peer(RR,_myIdentity,*id));
{
Mutex::Lock l2(_peers_l);
_peers.set(id->address(),p);
}
if (!f(p,v->phy()))
return;
}
}
}
}
}
{
Mutex::Lock l(_staticRoots_l);
Hashtable< Identity,std::vector<InetAddress> >::Iterator i(_staticRoots);
Identity *k = (Identity *)0;
std::vector<InetAddress> *v = (std::vector<InetAddress> *)0;
while (i.next(k,v)) {
if (!v->empty()) {
const SharedPtr<Peer> *ap; const SharedPtr<Peer> *ap;
{ {
Mutex::Lock l2(_peers_l); Mutex::Lock l2(_peers_l);
ap = _peers.get(k->address()); ap = _peers.get(id->address());
} }
if (ap) { if (ap) {
if (!f(*ap,*v)) if (!f(*ap,v->phy()))
return; return;
} else { } else {
SharedPtr<Peer> p(new Peer(RR,_myIdentity,*k)); SharedPtr<Peer> p(new Peer(RR,_myIdentity,*id));
{ {
Mutex::Lock l2(_peers_l); Mutex::Lock l2(_peers_l);
_peers.set(k->address(),p); _peers.set(id->address(),p);
} }
if (!f(p,*v)) if (!f(p,v->phy()))
return; return;
} }
} }
@ -335,49 +301,17 @@ public:
} }
/** /**
* Set or update a static root entry * Iterate through all root names
*
* @param id Static root's identity
* @param addrs Static root's IP address(es)
*/
inline void setStaticRoot(const Identity &id,const std::vector<InetAddress> &addrs)
{
Mutex::Lock l(_staticRoots_l);
_staticRoots[id] = addrs;
}
/**
* Remove a static root
*
* @param id Identity to remove
*/
inline void removeStaticRoot(const Identity &id)
{
Mutex::Lock l(_staticRoots_l);
_staticRoots.erase(id);
}
/**
* Clear all static roots
*/
inline void removeStaticRoot()
{
Mutex::Lock l(_staticRoots_l);
_staticRoots.clear();
}
/**
* Iterate through all dynamic roots
* *
* @param f Function of (Str,Locator) * @param f Function of (Str,Locator)
*/ */
template<typename F> template<typename F>
ZT_ALWAYS_INLINE void eachDynamicRoot(F f) const ZT_ALWAYS_INLINE void eachRootName(F f) const
{ {
Mutex::Lock l(_dynamicRoots_l); Mutex::Lock l(_roots_l);
Str *k = (Str *)0; Str *k = (Str *)0;
Locator *v = (Locator *)0; Locator *v = (Locator *)0;
Hashtable< Str,Locator >::Iterator i(const_cast<Topology *>(this)->_dynamicRoots); Hashtable< Str,Locator >::Iterator i(const_cast<Topology *>(this)->_roots);
while (i.next(k,v)) { while (i.next(k,v)) {
if (!f(*k,*v)) if (!f(*k,*v))
break; break;
@ -389,22 +323,22 @@ public:
* *
* This does not check signatures or internal validity of the locator. * This does not check signatures or internal validity of the locator.
* *
* @param dnsName DNS name used to retrive root * @param name DNS name used to retrive root or simply the address for static roots
* @param latestLocator Latest locator * @param latestLocator Latest locator
* @return True if locator is newer or if a new entry was created * @return True if locator is newer or if a new entry was created
*/ */
inline bool setDynamicRoot(const Str &dnsName,const Locator &latestLocator) inline bool setRoot(const Str &name,const Locator &latestLocator)
{ {
Mutex::Lock l(_dynamicRoots_l); Mutex::Lock l(_roots_l);
if (latestLocator) { if (latestLocator) {
Locator &ll = _dynamicRoots[dnsName]; Locator &ll = _roots[name];
if (ll.timestamp() < latestLocator.timestamp()) { if (ll.timestamp() < latestLocator.timestamp()) {
ll = latestLocator; ll = latestLocator;
_updateDynamicRootIdentities(); _updateDynamicRootIdentities();
return true; return true;
} }
} else if (!_dynamicRoots.contains(dnsName)) { } else if (!_roots.contains(name)) {
_dynamicRoots[dnsName]; _roots[name];
return true; return true;
} }
return false; return false;
@ -412,39 +346,26 @@ public:
/** /**
* Remove a dynamic root entry * Remove a dynamic root entry
*
* @param dnsName DNS name to remove
*/ */
inline void removeDynamicRoot(const Str &dnsName) inline void removeRoot(const Str &name)
{ {
Mutex::Lock l(_dynamicRoots_l); Mutex::Lock l(_roots_l);
_dynamicRoots.erase(dnsName); _roots.erase(name);
_updateDynamicRootIdentities(); _updateDynamicRootIdentities();
} }
/**
* Remove all dynamic roots
*/
inline void clearDynamicRoots()
{
Mutex::Lock l(_dynamicRoots_l);
_dynamicRoots.clear();
_dynamicRootIdentities.clear();
}
/** /**
* @param Current time * @param Current time
* @return ZT_RootList as returned by the external CAPI * @return ZT_RootList as returned by the external CAPI
*/ */
inline ZT_RootList *apiRoots(const int64_t now) const inline ZT_RootList *apiRoots(const int64_t now) const
{ {
Mutex::Lock l1(_staticRoots_l); Mutex::Lock l2(_roots_l);
Mutex::Lock l2(_dynamicRoots_l);
// The memory allocated here has room for all roots plus the maximum size // The memory allocated here has room for all roots plus the maximum size
// of their DNS names, identities, and up to 16 physical addresses. Most // of their DNS names, identities, and up to 16 physical addresses. Most
// roots will have two: one V4 and one V6. // roots will have two: one V4 and one V6.
const unsigned int totalRoots = _staticRoots.size() + _dynamicRoots.size(); const unsigned int totalRoots = _roots.size();
ZT_RootList *rl = reinterpret_cast<ZT_RootList *>(malloc(sizeof(ZT_RootList) + (sizeof(ZT_Root) * totalRoots) + ((sizeof(struct sockaddr_storage) * ZT_MAX_PEER_NETWORK_PATHS) * totalRoots) + ((ZT_IDENTITY_STRING_BUFFER_LENGTH + 1024) * totalRoots))); ZT_RootList *rl = reinterpret_cast<ZT_RootList *>(malloc(sizeof(ZT_RootList) + (sizeof(ZT_Root) * totalRoots) + ((sizeof(struct sockaddr_storage) * ZT_MAX_PEER_NETWORK_PATHS) * totalRoots) + ((ZT_IDENTITY_STRING_BUFFER_LENGTH + 1024) * totalRoots)));
if (!rl) { if (!rl) {
return nullptr; return nullptr;
@ -462,7 +383,7 @@ public:
{ {
Str *k = (Str *)0; Str *k = (Str *)0;
Locator *v = (Locator *)0; Locator *v = (Locator *)0;
Hashtable< Str,Locator >::Iterator i(const_cast<Topology *>(this)->_dynamicRoots); Hashtable< Str,Locator >::Iterator i(const_cast<Topology *>(this)->_roots);
while (i.next(k,v)) { while (i.next(k,v)) {
rl->roots[c].dnsName = nameBufPtr; rl->roots[c].dnsName = nameBufPtr;
const char *p = k->c_str(); const char *p = k->c_str();
@ -494,35 +415,6 @@ public:
} }
} }
{
Hashtable< Identity,std::vector<InetAddress> >::Iterator i(const_cast<Topology *>(this)->_staticRoots);
Identity *k = (Identity *)0;
std::vector<InetAddress> *v = (std::vector<InetAddress> *)0;
while (i.next(k,v)) {
rl->roots[c].dnsName = nullptr;
rl->roots[c].identity = nameBufPtr;
k->toString(false,nameBufPtr);
nameBufPtr += strlen(nameBufPtr) + 1;
rl->roots[c].addresses = addrBuf;
unsigned int ac = 0;
for(unsigned int j=(unsigned int)v->size();(ac<j)&&(ac<16);++ac)
*(addrBuf++) = (*v)[ac];
rl->roots[c].addressCount = ac;
_peers_l.lock();
const SharedPtr<Peer> *psptr = _peers.get(k->address());
if (psptr) {
rl->roots[c].preferred = (psptr->ptr() == bestRootPtr) ? 1 : 0;
rl->roots[c].online = (*psptr)->alive(now) ? 1 : 0;
}
_peers_l.unlock();
++c;
}
}
rl->count = c; rl->count = c;
return rl; return rl;
@ -668,18 +560,15 @@ private:
Hashtable< Address,SharedPtr<Peer> > _peers; Hashtable< Address,SharedPtr<Peer> > _peers;
Hashtable< Path::HashKey,SharedPtr<Path> > _paths; Hashtable< Path::HashKey,SharedPtr<Path> > _paths;
Hashtable< Str,Locator > _roots;
Hashtable< Str,Locator > _dynamicRoots; Hashtable< Identity,bool > _rootIdentities;
Hashtable< Identity,bool > _dynamicRootIdentities;
Hashtable< Identity,std::vector<InetAddress> > _staticRoots;
int64_t _lastUpdatedBestRoot; int64_t _lastUpdatedBestRoot;
SharedPtr<Peer> _bestRoot; SharedPtr<Peer> _bestRoot;
Mutex _peers_l; Mutex _peers_l;
Mutex _paths_l; Mutex _paths_l;
Mutex _dynamicRoots_l; Mutex _roots_l;
Mutex _staticRoots_l;
Mutex _bestRoot_l; Mutex _bestRoot_l;
}; };