From e5f7c55c5495369c091ab5aec449638d7abd5a50 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 6 Jul 2015 12:34:35 -0700 Subject: Documentation in Packet, more work on path push, and clean up ancient legacy support code in Switch. --- node/Switch.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'node/Switch.cpp') diff --git a/node/Switch.cpp b/node/Switch.cpp index 236c1e66..18e17a60 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -167,6 +167,8 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c Address toZT(to.toAddress(network->id())); if (network->isAllowed(toZT)) { + const bool includeCom = network->peerNeedsOurMembershipCertificate(toZT,RR->node->now()); + /* if (network->peerNeedsOurMembershipCertificate(toZT,RR->node->now())) { // TODO: once there are no more <1.0.0 nodes around, we can // bundle this with EXT_FRAME instead of sending two packets. @@ -174,12 +176,17 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c nconf->com().serialize(outp); send(outp,true,network->id()); } + */ - if (fromBridged) { - // EXT_FRAME is used for bridging or if we want to include a COM + if ((true)||(fromBridged)||(includeCom)) { Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); - outp.append((unsigned char)0); + if (includeCom) { + outp.append((unsigned char)0x01); // 0x01 -- COM included + nconf->com().serialize(outp); + } else { + outp.append((unsigned char)0x00); + } to.appendTo(outp); from.appendTo(outp); outp.append((uint16_t)etherType); @@ -187,7 +194,6 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c outp.compress(); send(outp,true,network->id()); } else { - // FRAME is a shorter version that can be used when there's no bridging and no COM Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME); outp.append(network->id()); outp.append((uint16_t)etherType); @@ -196,7 +202,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c send(outp,true,network->id()); } - //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged); + //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d includeCom==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged,(int)includeCom); } else { TRACE("%.16llx: UNICAST: %s -> %s etherType==%s dropped, destination not a member of private network",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); } -- cgit v1.2.3 From 35b5dcf89df77e372c8c06e62b30debd55426f98 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 6 Jul 2015 12:39:20 -0700 Subject: Kill debug line. --- node/Switch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node/Switch.cpp') diff --git a/node/Switch.cpp b/node/Switch.cpp index 18e17a60..f91bf5c9 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -178,7 +178,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c } */ - if ((true)||(fromBridged)||(includeCom)) { + if ((fromBridged)||(includeCom)) { Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); if (includeCom) { -- cgit v1.2.3 From 6bfbc43e3c1de27648c974fc783573487391e0a2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 6 Jul 2015 12:46:27 -0700 Subject: Include COM with EXT_FRAME in bridged case. --- node/Switch.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'node/Switch.cpp') diff --git a/node/Switch.cpp b/node/Switch.cpp index f91bf5c9..f022122e 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -167,7 +167,6 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c Address toZT(to.toAddress(network->id())); if (network->isAllowed(toZT)) { - const bool includeCom = network->peerNeedsOurMembershipCertificate(toZT,RR->node->now()); /* if (network->peerNeedsOurMembershipCertificate(toZT,RR->node->now())) { // TODO: once there are no more <1.0.0 nodes around, we can @@ -178,6 +177,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c } */ + const bool includeCom = network->peerNeedsOurMembershipCertificate(toZT,RR->node->now()); if ((fromBridged)||(includeCom)) { Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); @@ -216,16 +216,14 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c Address bridges[ZT_MAX_BRIDGE_SPAM]; unsigned int numBridges = 0; + /* Create an array of up to ZT_MAX_BRIDGE_SPAM recipients for this bridged frame. */ bridges[0] = network->findBridgeTo(to); if ((bridges[0])&&(bridges[0] != RR->identity.address())&&(network->isAllowed(bridges[0]))&&(network->permitsBridging(bridges[0]))) { - // We have a known bridge route for this MAC. + /* We have a known bridge route for this MAC, send it there. */ ++numBridges; } else if (!nconf->activeBridges().empty()) { /* If there is no known route, spam to up to ZT_MAX_BRIDGE_SPAM active - * bridges. This is similar to what many switches do -- if they do not - * know which port corresponds to a MAC, they send it to all ports. If - * there aren't any active bridges, numBridges will stay 0 and packet - * is dropped. */ + * bridges. If someone responds, we'll learn the route. */ std::vector
::const_iterator ab(nconf->activeBridges().begin()); if (nconf->activeBridges().size() <= ZT_MAX_BRIDGE_SPAM) { // If there are <= ZT_MAX_BRIDGE_SPAM active bridges, spam them all @@ -251,7 +249,12 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c for(unsigned int b=0;bidentity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); - outp.append((unsigned char)0); + if (network->peerNeedsOurMembershipCertificate(bridges[b],RR->node->now())) { + outp.append((unsigned char)0x01); // 0x01 -- COM included + nconf->com().serialize(outp); + } else { + outp.append((unsigned char)0); + } to.appendTo(outp); from.appendTo(outp); outp.append((uint16_t)etherType); -- cgit v1.2.3 From 93bb934d4e77fd1436ebe81336d396fa769aa59b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 6 Jul 2015 14:08:13 -0700 Subject: Some cleanup, docs, and Path -> Path > RemotePath refactor. --- node/Node.cpp | 6 +-- node/Packet.hpp | 32 ++++++++++---- node/Path.hpp | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ node/Peer.cpp | 15 ++++--- node/Peer.hpp | 36 +++++++++------- node/RemotePath.hpp | 97 ++++++++++-------------------------------- node/SelfAwareness.cpp | 2 +- node/Switch.cpp | 2 +- node/Topology.cpp | 2 +- 9 files changed, 197 insertions(+), 108 deletions(-) create mode 100644 node/Path.hpp (limited to 'node/Switch.cpp') diff --git a/node/Node.cpp b/node/Node.cpp index 8cdc6d62..8eacf753 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -388,10 +388,10 @@ ZT1_PeerList *Node::peers() const p->latency = pi->second->latency(); p->role = RR->topology->isRoot(pi->second->identity()) ? ZT1_PEER_ROLE_ROOT : ZT1_PEER_ROLE_LEAF; - std::vector paths(pi->second->paths()); - Path *bestPath = pi->second->getBestPath(_now); + std::vector paths(pi->second->paths()); + RemotePath *bestPath = pi->second->getBestPath(_now); p->pathCount = 0; - for(std::vector::iterator path(paths.begin());path!=paths.end();++path) { + for(std::vector::iterator path(paths.begin());path!=paths.end();++path) { memcpy(&(p->paths[p->pathCount].address),&(path->address()),sizeof(struct sockaddr_storage)); p->paths[p->pathCount].lastSend = path->lastSend(); p->paths[p->pathCount].lastReceive = path->lastReceived(); diff --git a/node/Packet.hpp b/node/Packet.hpp index 5572e235..14fac1bf 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -899,16 +899,17 @@ public: * Path record format: * <[1] flags> * <[1] metric from 0 (highest priority) to 255 (lowest priority)> + * <[2] length of extended path characteristics or 0 for none> + * <[...] extended path characteristics> * <[1] address type> * <[...] address> * * Path record flags: - * 0x01 - Blacklist this path, do not use - * 0x02 - Reliable path (no keepalives, etc. necessary) - * 0x04 - Trusted path (encryption and authentication optional) - * - * None of the above flags are implemented yet as of 1.0.4. They're - * reserved for future use. + * 0x01 - Forget this path if it is currently known + * 0x02 - Blacklist this path, do not use + * 0x04 - Reliable path (no NAT keepalives, etc. are necessary) + * 0x08 - Disable encryption (trust: privacy) + * 0x10 - Disable encryption and authentication (trust: ultimate) * * Address types and addresses are of the same format as the destination * address type and address in HELLO. @@ -916,9 +917,24 @@ public: * The receiver may, upon receiving a push, attempt to establish a * direct link to one or more of the indicated addresses. It is the * responsibility of the sender to limit which peers it pushes direct - * paths to to those with whom it has a trust relationship. + * paths to to those with whom it has a trust relationship. The receiver + * must obey any restrictions provided such as exclusivity or blacklists. + * OK responses to this message are optional. * - * OK/ERROR are not generated. + * Note that a direct path push does not imply that learned paths can't + * be used unless they are blacklisted explicitly or unless flag 0x01 + * is set. + * + * Only a subset of this functionality is currently implemented: basic + * path pushing and learning. Metrics, most flags, and OK responses are + * not yet implemented as of 1.0.4. + * + * OK response payload: + * <[2] 16-bit number of active direct paths we already have> + * <[2] 16-bit number of paths in push that we don't already have> + * <[2] 16-bit number of new paths we are trying (or will try)> + * + * ERROR is presently not sent. */ VERB_PUSH_DIRECT_PATHS = 16 }; diff --git a/node/Path.hpp b/node/Path.hpp new file mode 100644 index 00000000..b43b3f6d --- /dev/null +++ b/node/Path.hpp @@ -0,0 +1,113 @@ +/* + * ZeroTier One - Network Virtualization Everywhere + * Copyright (C) 2011-2015 ZeroTier, Inc. + * + * 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 . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +#ifndef ZT_PATH_HPP +#define ZT_PATH_HPP + +#include "Constants.hpp" +#include "InetAddress.hpp" +#include "Utils.hpp" + +namespace ZeroTier { + +class Path +{ +public: + enum Trust + { + TRUST_NORMAL, + TRUST_PRIVACY, + TRUST_ULTIMATE + }; + + Path() : + _addr(), + _metric(0), + _trust(TRUST_NORMAL), + _reliable(false), + _fixed(false) + { + } + + Path(const InetAddress &addr,int metric,Trust trust,bool reliable,bool fixed) : + _addr(addr), + _metric(metric), + _trust(trust), + _reliable(reliable), + _fixed(fixed) + { + } + + /** + * @return Physical address + */ + inline const InetAddress &address() const throw() { return _addr; } + + /** + * @return Metric (higher == worse) or negative if path is blacklisted + */ + inline int metric() const throw() { return _metric; } + + /** + * @return Path trust level + */ + inline Trust trust() const throw() { return _trust; } + + /** + * @return True if path is considered reliable (no NAT keepalives etc. are needed) + */ + inline bool reliable() const throw() { return _reliable; } + + /** + * @return Is this a fixed path? + */ + inline bool fixed() const throw() { return _fixed; } + + /** + * @return True if address is non-NULL + */ + inline operator bool() const throw() { return (_addr); } + + // Comparisons are by address only + inline bool operator==(const Path &p) const throw() { return (_addr == p._addr); } + inline bool operator!=(const Path &p) const throw() { return (_addr != p._addr); } + inline bool operator<(const Path &p) const throw() { return (_addr < p._addr); } + inline bool operator>(const Path &p) const throw() { return (_addr > p._addr); } + inline bool operator<=(const Path &p) const throw() { return (_addr <= p._addr); } + inline bool operator>=(const Path &p) const throw() { return (_addr >= p._addr); } + +protected: + InetAddress _addr; + int _metric; // negative == blacklisted + Trust _trust; + bool _reliable; + bool _fixed; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/Peer.cpp b/node/Peer.cpp index 96caa72c..cb046b9b 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -46,6 +46,7 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity) _lastMulticastFrame(0), _lastAnnouncedTo(0), _lastPathConfirmationSent(0), + _lastDirectPathPush(0), _vMajor(0), _vMinor(0), _vRevision(0), @@ -86,7 +87,7 @@ void Peer::received( if (!pathIsConfirmed) { if ((verb == Packet::VERB_OK)&&(inReVerb == Packet::VERB_HELLO)) { // Learn paths if they've been confirmed via a HELLO - Path *slot = (Path *)0; + RemotePath *slot = (RemotePath *)0; if (np < ZT1_MAX_PEER_NETWORK_PATHS) { // Add new path slot = &(_paths[np++]); @@ -101,7 +102,7 @@ void Peer::received( } } if (slot) { - slot->init(remoteAddr,false); + *slot = RemotePath(remoteAddr,false); slot->received(now); _numPaths = np; pathIsConfirmed = true; @@ -193,7 +194,7 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &at void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) { - Path *const bestPath = getBestPath(now); + RemotePath *const bestPath = getBestPath(now); if ((bestPath)&&(bestPath->active(now))) { if ((now - bestPath->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) { TRACE("PING %s(%s)",_id.address().toString().c_str(),bestPath->address().toString().c_str()); @@ -207,7 +208,11 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) } } -void Peer::addPath(const Path &newp) +//void Peer::pushDirectPaths(const std::vector &dps,uint64_t now,bool force) +//{ +//} + +void Peer::addPath(const RemotePath &newp) { unsigned int np = _numPaths; @@ -218,7 +223,7 @@ void Peer::addPath(const Path &newp) } } - Path *slot = (Path *)0; + RemotePath *slot = (RemotePath *)0; if (np < ZT1_MAX_PEER_NETWORK_PATHS) { // Add new path slot = &(_paths[np++]); diff --git a/node/Peer.hpp b/node/Peer.hpp index 8d8b7cb4..6ca29393 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -40,7 +40,7 @@ #include "../include/ZeroTierOne.h" #include "RuntimeEnvironment.hpp" -#include "Path.hpp" +#include "RemotePath.hpp" #include "Address.hpp" #include "Utils.hpp" #include "Identity.hpp" @@ -53,11 +53,7 @@ namespace ZeroTier { /** - * Peer on P2P Network - * - * This struture is not locked, volatile, and memcpy-able. NonCopyable - * semantics are just there to prevent bugs, not because it isn't safe - * to copy. + * Peer on P2P Network (virtual layer 1) */ class Peer : NonCopyable { @@ -130,9 +126,9 @@ public: * @param now Current time * @return Best path or NULL if there are no active (or fixed) direct paths */ - inline Path *getBestPath(uint64_t now) + inline RemotePath *getBestPath(uint64_t now) { - Path *bestPath = (Path *)0; + RemotePath *bestPath = (RemotePath *)0; uint64_t lrMax = 0; for(unsigned int p=0,np=_numPaths;p= lrMax)) { @@ -152,14 +148,14 @@ public: * @param now Current time * @return Path used on success or NULL on failure */ - inline Path *send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) + inline RemotePath *send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) { - Path *bestPath = getBestPath(now); + RemotePath *bestPath = getBestPath(now); if (bestPath) { if (bestPath->send(RR,data,len,now)) return bestPath; } - return (Path *)0; + return (RemotePath *)0; } /** @@ -182,12 +178,21 @@ public: */ void doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now); + /** + * Push direct paths (if within rate limit) + * + * @param dps Direct paths to me to push to this peer + * @param now Current time + * @param force If true, force regardless of when we pushed direct paths last + */ + void pushDirectPaths(const std::vector &dps,uint64_t now,bool force); + /** * @return All known direct paths to this peer */ - inline std::vector paths() const + inline std::vector paths() const { - std::vector pp; + std::vector pp; for(unsigned int p=0,np=_numPaths;p #include #include -#include #include -#include "Constants.hpp" +#include "Path.hpp" #include "Node.hpp" -#include "InetAddress.hpp" -#include "Utils.hpp" #include "AntiRecursion.hpp" #include "RuntimeEnvironment.hpp" namespace ZeroTier { /** - * WAN address and protocol for reaching a peer + * Path to a remote peer * - * This structure is volatile and memcpy-able, and depends on - * InetAddress being similarly safe. + * This extends Path to include status information about path activity. */ -class Path +class RemotePath : public Path { public: - Path() : - _addr(), + RemotePath() : + Path(), _lastSend(0), - _lastReceived(0), - _fixed(false) {} + _lastReceived(0) {} - Path(const Path &p) throw() { memcpy(this,&p,sizeof(Path)); } - - Path(const InetAddress &addr,bool fixed) : - _addr(addr), + RemotePath(const InetAddress &addr,bool fixed) : + Path(addr,0,TRUST_NORMAL,false,fixed), _lastSend(0), - _lastReceived(0), - _fixed(fixed) {} + _lastReceived(0) {} - inline void init(const InetAddress &addr,bool fixed) - { - _addr = addr; - _lastSend = 0; - _lastReceived = 0; - _fixed = fixed; - } + inline uint64_t lastSend() const throw() { return _lastSend; } + inline uint64_t lastReceived() const throw() { return _lastReceived; } - inline Path &operator=(const Path &p) + /** + * @param f New value of parent 'fixed' field + */ + inline void setFixed(const bool f) + throw() { - if (this != &p) - memcpy(this,&p,sizeof(Path)); - return *this; + _fixed = f; } - inline const InetAddress &address() const throw() { return _addr; } - - inline uint64_t lastSend() const throw() { return _lastSend; } - inline uint64_t lastReceived() const throw() { return _lastReceived; } - /** - * Called when a packet is sent to this path + * Called when a packet is sent to this remote path * - * This is called automatically by Path::send(). + * This is called automatically by RemotePath::send(). * * @param t Time of send */ @@ -101,7 +85,7 @@ public: } /** - * Called when a packet is received from this path + * Called when a packet is received from this remote path * * @param t Time of receive */ @@ -111,16 +95,6 @@ public: _lastReceived = t; } - /** - * @return Is this a fixed path? - */ - inline bool fixed() const throw() { return _fixed; } - - /** - * @param f New value of fixed path flag - */ - inline void setFixed(bool f) throw() { _fixed = f; } - /** * @param now Current time * @return True if this path is fixed or has received data in last ACTIVITY_TIMEOUT ms @@ -150,34 +124,9 @@ public: return false; } - /** - * @param now Current time - * @return Human-readable address and other information about this path - */ - inline std::string toString(uint64_t now) const - { - char tmp[1024]; - Utils::snprintf(tmp,sizeof(tmp),"%s(%s)", - _addr.toString().c_str(), - ((_fixed) ? "fixed" : (active(now) ? "active" : "inactive")) - ); - return std::string(tmp); - } - - inline operator bool() const throw() { return (_addr); } - - inline bool operator==(const Path &p) const throw() { return (_addr == p._addr); } - inline bool operator!=(const Path &p) const throw() { return (_addr != p._addr); } - inline bool operator<(const Path &p) const throw() { return (_addr < p._addr); } - inline bool operator>(const Path &p) const throw() { return (_addr > p._addr); } - inline bool operator<=(const Path &p) const throw() { return (_addr <= p._addr); } - inline bool operator>=(const Path &p) const throw() { return (_addr >= p._addr); } - private: - InetAddress _addr; uint64_t _lastSend; uint64_t _lastReceived; - bool _fixed; }; } // namespace ZeroTier diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 9f7c41d7..00015788 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -120,7 +120,7 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &reporterPhysi // they are still considered alive so that we will re-establish direct links. SharedPtr sn(RR->topology->getBestRoot()); if (sn) { - Path *snp = sn->getBestPath(now); + RemotePath *snp = sn->getBestPath(now); if (snp) { for(std::vector< SharedPtr >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) { if ((*p)->alive(now)) { diff --git a/node/Switch.cpp b/node/Switch.cpp index f022122e..891c4a45 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -733,7 +733,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) if (peer) { const uint64_t now = RR->node->now(); - Path *viaPath = peer->getBestPath(now); + RemotePath *viaPath = peer->getBestPath(now); if (!viaPath) { SharedPtr relay; diff --git a/node/Topology.cpp b/node/Topology.cpp index 2b1cc31f..b255080e 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -62,7 +62,7 @@ void Topology::setRootServers(const std::map< Identity,std::vector if (!p) p = SharedPtr(new Peer(RR->identity,i->first)); for(std::vector::const_iterator j(i->second.begin());j!=i->second.end();++j) - p->addPath(Path(*j,true)); + p->addPath(RemotePath(*j,true)); p->use(now); _rootPeers.push_back(p); } -- cgit v1.2.3 From fad9dff2db26662e1496329057884b3b928cb1c9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 6 Jul 2015 15:05:04 -0700 Subject: Almost all of GitHub issue #180 --- node/IncomingPacket.cpp | 6 ++++++ node/IncomingPacket.hpp | 1 + node/Node.hpp | 10 ++++++++++ node/Switch.cpp | 10 +++++++++- 4 files changed, 26 insertions(+), 1 deletion(-) (limited to 'node/Switch.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index f45a1279..7634f54f 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -84,6 +84,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) case Packet::VERB_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer); case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); + case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); } } else { RR->sw->requestWhois(source()); @@ -882,6 +883,11 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share return true; } +bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer) +{ + return true; +} + void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr &peer,uint64_t nwid) { Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 174fa38d..3bf7737d 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -121,6 +121,7 @@ private: bool _doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); + bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer); // Send an ERROR_NEED_MEMBERSHIP_CERTIFICATE to a peer indicating that an updated cert is needed to join void _sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr &peer,uint64_t nwid); diff --git a/node/Node.hpp b/node/Node.hpp index 2d2898b5..5c7cfae2 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -43,6 +43,7 @@ #include "Mutex.hpp" #include "MAC.hpp" #include "Network.hpp" +#include "Path.hpp" #undef TRACE #ifdef ZT_TRACE @@ -171,6 +172,12 @@ public: return nw; } + inline std::vector directPaths() const + { + Mutex::Lock _l(_directPaths_m); + return _directPaths; + } + inline bool dataStorePut(const char *name,const void *data,unsigned int len,bool secure) { return (_dataStorePutFunction(reinterpret_cast(this),_uPtr,name,data,len,(int)secure) == 0); } inline bool dataStorePut(const char *name,const std::string &data,bool secure) { return dataStorePut(name,(const void *)data.data(),(unsigned int)data.length(),secure); } inline void dataStoreDelete(const char *name) { _dataStorePutFunction(reinterpret_cast(this),_uPtr,name,(const void *)0,0,0); } @@ -236,6 +243,9 @@ private: std::vector< std::pair< uint64_t, SharedPtr > > _networks; Mutex _networks_m; + std::vector _directPaths; + Mutex _directPaths_m; + Mutex _backgroundTasksLock; uint64_t _now; diff --git a/node/Switch.cpp b/node/Switch.cpp index 891c4a45..7600624f 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -733,10 +733,16 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) if (peer) { const uint64_t now = RR->node->now(); + if (nwid) { + // If this packet has an associated network, give the peer additional hints for direct connectivity + peer->pushDirectPaths(RR,RR->node->directPaths(),now,false); + } + RemotePath *viaPath = peer->getBestPath(now); if (!viaPath) { SharedPtr relay; + // See if this network has a preferred relay (if packet has an associated network) if (nwid) { SharedPtr network(RR->node->network(nwid)); if (network) { @@ -754,6 +760,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) } } + // Otherwise relay off a root server if (!relay) relay = RR->topology->getBestRoot(); @@ -770,7 +777,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) if (viaPath->send(RR,tmp.data(),chunkSize,now)) { if (chunkSize < tmp.size()) { - // Too big for one bite, fragment the rest + // Too big for one packet, fragment the rest unsigned int fragStart = chunkSize; unsigned int remaining = tmp.size() - chunkSize; unsigned int fragsRemaining = (remaining / (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)); @@ -786,6 +793,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) remaining -= chunkSize; } } + return true; } } else { -- cgit v1.2.3 From 79e9a8bcc26491a43577082ec7edb86020f7ec00 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 6 Jul 2015 15:28:48 -0700 Subject: Almost everything for GitHub issue #180 except direct path map setup. --- node/Constants.hpp | 10 ---------- node/IncomingPacket.cpp | 30 ++++++++++++++++++++++++++++++ node/Node.cpp | 16 +--------------- node/Node.hpp | 1 - node/Packet.hpp | 21 +-------------------- node/Peer.cpp | 6 +++++- node/Switch.cpp | 24 ++---------------------- node/Switch.hpp | 2 -- 8 files changed, 39 insertions(+), 71 deletions(-) (limited to 'node/Switch.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 1f0d8426..d15fef13 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -304,16 +304,6 @@ */ #define ZT_ANTIRECURSION_HISTORY_SIZE 16 -/** - * How often to send LAN beacons - */ -#define ZT_BEACON_INTERVAL 30000 - -/** - * Do not respond to any beacon more often than this - */ -#define ZT_MIN_BEACON_RESPONSE_INTERVAL 2500 - /** * Minimum delay between attempts to confirm new paths to peers (to avoid HELLO flooding) */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 7634f54f..87669ba7 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -885,6 +885,36 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer) { + try { + unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); + unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; + + while (count) { // if ptr overflows Buffer will throw + unsigned int flags = (*this)[ptr++]; + /*int metric = (*this)[ptr++];*/ ++ptr; + unsigned int extLen = at(ptr); ptr += 2; + ptr += extLen; // unused right now + unsigned int addrType = (*this)[ptr++]; + unsigned int addrLen = (*this)[ptr++]; + switch(addrType) { + case 4: { + InetAddress a(field(ptr,4),4,at(ptr + 4)); + if ((flags & (0x01 | 0x02)) == 0) + peer->attemptToContactAt(RR,a,RR->node->now()); + } break; + case 6: { + InetAddress a(field(ptr,16),16,at(ptr + 16)); + if ((flags & (0x01 | 0x02)) == 0) + peer->attemptToContactAt(RR,a,RR->node->now()); + } break; + } + ptr += addrLen; + } + } catch (std::exception &exc) { + TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); + } catch ( ... ) { + TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str()); + } return true; } diff --git a/node/Node.cpp b/node/Node.cpp index 8eacf753..7c70db97 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -78,8 +78,7 @@ Node::Node( _networks_m(), _now(now), _lastPingCheck(0), - _lastHousekeepingRun(0), - _lastBeacon(0) + _lastHousekeepingRun(0) { _newestVersionSeen[0] = ZEROTIER_ONE_VERSION_MAJOR; _newestVersionSeen[1] = ZEROTIER_ONE_VERSION_MINOR; @@ -269,19 +268,6 @@ ZT1_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *next _online = ((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT); if (oldOnline != _online) postEvent(_online ? ZT1_EVENT_ONLINE : ZT1_EVENT_OFFLINE); - - // Send LAN beacons - if ((now - _lastBeacon) >= ZT_BEACON_INTERVAL) { - _lastBeacon = now; - char beacon[13]; - void *p = beacon; - *(reinterpret_cast(p)) = RR->prng->next32(); - p = beacon + 4; - *(reinterpret_cast(p)) = RR->prng->next32(); - RR->identity.address().copyTo(beacon + 8,5); - RR->antiRec->logOutgoingZT(beacon,13); - putPacket(ZT_DEFAULTS.v4Broadcast,beacon,13); - } } catch ( ... ) { return ZT1_RESULT_FATAL_ERROR_INTERNAL; } diff --git a/node/Node.hpp b/node/Node.hpp index 5c7cfae2..cd8d68fc 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -251,7 +251,6 @@ private: uint64_t _now; uint64_t _lastPingCheck; uint64_t _lastHousekeepingRun; - uint64_t _lastBeacon; unsigned int _newestVersionSeen[3]; // major, minor, revision bool _online; }; diff --git a/node/Packet.hpp b/node/Packet.hpp index 9b86709a..50471b06 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -233,16 +233,6 @@ */ #define ZT_PROTO_MIN_FRAGMENT_LENGTH ZT_PACKET_FRAGMENT_IDX_PAYLOAD -/** - * DEPRECATED: length of LAN beacon packets - */ -#define ZT_PROTO_BEACON_LENGTH 13 - -/** - * DEPRECATED: index of address in a LAN beacon - */ -#define ZT_PROTO_BEACON_IDX_ADDRESS 8 - // Destination address types from HELLO, OK(HELLO), and other message types #define ZT_PROTO_DEST_ADDRESS_TYPE_NONE 0 #define ZT_PROTO_DEST_ADDRESS_TYPE_ZEROTIER 1 // reserved but unused @@ -388,16 +378,6 @@ namespace ZeroTier { * * For unencrypted packets, MAC is computed on plaintext. Only HELLO is ever * sent in the clear, as it's the "here is my public key" message. - * - * Beacon format and beacon packets: - * <[8] 8 random bytes> - * <[5] sender ZT address> - * - * A beacon is a 13-byte packet containing only the address of the sender. - * Receiving peers may or may not respond to beacons with a HELLO or other - * message to initiate direct communication. - * - * Beacons may be used for direct LAN announcement or NAT traversal. */ class Packet : public Buffer { @@ -901,6 +881,7 @@ public: * <[2] length of extended path characteristics or 0 for none> * <[...] extended path characteristics> * <[1] address type> + * <[1] address length in bytes> * <[...] address> * * Path record flags: diff --git a/node/Peer.cpp b/node/Peer.cpp index ec04357a..225fbdef 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -210,9 +210,12 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) void Peer::pushDirectPaths(const RuntimeEnvironment *RR,const std::vector &dps,uint64_t now,bool force) { - if (((now - _lastDirectPathPush) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force)) { + if ((!dps.empty())&&(((now - _lastDirectPathPush) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force))) { _lastDirectPathPush = now; + TRACE("pushing %u direct paths to %s",(unsigned int)dps.size(),_id.address().toString().c_str()); + printf("pushing %u direct paths to %s",(unsigned int)dps.size(),_id.address().toString().c_str()); + std::vector::const_iterator p(dps.begin()); while (p != dps.end()) { Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); @@ -254,6 +257,7 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,const std::vector outp.append((uint8_t)((p->metric() >= 0) ? ((p->metric() <= 255) ? p->metric() : 255) : 0)); outp.append((uint16_t)0); outp.append(addressType); + outp.append((addressType == 4) ? 6 : 18); outp.append(p->address().rawIpData(),((addressType == 4) ? 4 : 16)); outp.append((uint16_t)p->address().port()); diff --git a/node/Switch.cpp b/node/Switch.cpp index 7600624f..6a0b07cd 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -49,8 +49,7 @@ namespace ZeroTier { Switch::Switch(const RuntimeEnvironment *renv) : - RR(renv), - _lastBeacon(0) + RR(renv) { } @@ -61,9 +60,7 @@ Switch::~Switch() void Switch::onRemotePacket(const InetAddress &fromAddr,const void *data,unsigned int len) { try { - if (len == ZT_PROTO_BEACON_LENGTH) { - _handleBeacon(fromAddr,Buffer(data,len)); - } else if (len > ZT_PROTO_MIN_FRAGMENT_LENGTH) { + if (len > ZT_PROTO_MIN_FRAGMENT_LENGTH) { if (((const unsigned char *)data)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) { _handleRemotePacketFragment(fromAddr,data,len); } else if (len >= ZT_PROTO_MIN_PACKET_LENGTH) { @@ -696,23 +693,6 @@ void Switch::_handleRemotePacketHead(const InetAddress &fromAddr,const void *dat } } -void Switch::_handleBeacon(const InetAddress &fromAddr,const Buffer &data) -{ - Address beaconAddr(data.field(ZT_PROTO_BEACON_IDX_ADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - if (beaconAddr == RR->identity.address()) - return; - SharedPtr peer(RR->topology->getPeer(beaconAddr)); - if (peer) { - const uint64_t now = RR->node->now(); - if ((now - _lastBeacon) >= ZT_MIN_BEACON_RESPONSE_INTERVAL) { - _lastBeacon = now; - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); - outp.armor(peer->key(),false); - RR->node->putPacket(fromAddr,outp.data(),outp.size()); - } - } -} - Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) { SharedPtr root(RR->topology->getBestRoot(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); diff --git a/node/Switch.hpp b/node/Switch.hpp index 0ba4c138..af6e5938 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -183,12 +183,10 @@ public: private: void _handleRemotePacketFragment(const InetAddress &fromAddr,const void *data,unsigned int len); void _handleRemotePacketHead(const InetAddress &fromAddr,const void *data,unsigned int len); - void _handleBeacon(const InetAddress &fromAddr,const Buffer &data); Address _sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); bool _trySend(const Packet &packet,bool encrypt,uint64_t nwid); const RuntimeEnvironment *const RR; - volatile uint64_t _lastBeacon; // Outsanding WHOIS requests and how many retries they've undergone struct WhoisRequest -- cgit v1.2.3 From cac55105c3db6b0992b3ca6261b368bb14c7d144 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 6 Jul 2015 16:40:23 -0700 Subject: Fix a regression. --- node/OutboundMulticast.cpp | 2 -- node/Switch.cpp | 10 ---------- 2 files changed, 12 deletions(-) (limited to 'node/Switch.cpp') diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index bda7ab00..5809504a 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -106,8 +106,6 @@ void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toA if (!network) return; - if (!network->isAllowed(toAddr)) - return; if (_haveCom) { if (network->peerNeedsOurMembershipCertificate(toAddr,RR->node->now())) { diff --git a/node/Switch.cpp b/node/Switch.cpp index 6a0b07cd..201f36d1 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -164,16 +164,6 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c Address toZT(to.toAddress(network->id())); if (network->isAllowed(toZT)) { - /* - if (network->peerNeedsOurMembershipCertificate(toZT,RR->node->now())) { - // TODO: once there are no more <1.0.0 nodes around, we can - // bundle this with EXT_FRAME instead of sending two packets. - Packet outp(toZT,RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); - nconf->com().serialize(outp); - send(outp,true,network->id()); - } - */ - const bool includeCom = network->peerNeedsOurMembershipCertificate(toZT,RR->node->now()); if ((fromBridged)||(includeCom)) { Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME); -- cgit v1.2.3 From 778c7e6e703353030e2ea130e3db7cc968a5d53c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 7 Jul 2015 10:00:34 -0700 Subject: More cleanup to direct path push, comment fixes, etc. --- node/IncomingPacket.cpp | 17 +------- node/Network.hpp | 2 +- node/OutboundMulticast.cpp | 8 +--- node/Packet.hpp | 8 ++-- node/Peer.cpp | 10 +++-- node/Peer.hpp | 8 ++-- node/Switch.cpp | 98 +++++++++++++++++++++++----------------------- node/Switch.hpp | 5 ++- 8 files changed, 71 insertions(+), 85 deletions(-) (limited to 'node/Switch.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 7e883221..d5b4e9e6 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -661,21 +661,8 @@ bool IncomingPacket::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment ptr += com.deserialize(*this,ptr); if (com.hasRequiredFields()) { SharedPtr network(RR->node->network(com.networkId())); - if (network) { - if (network->validateAndAddMembershipCertificate(com)) { - if ((network->isAllowed(peer->address()))&&(network->peerNeedsOurMembershipCertificate(peer->address(),RR->node->now()))) { - // If peer passed our check and we haven't sent it our cert yet, respond - // and push our cert as well for instant authorization setup. - SharedPtr nconf(network->config2()); - if ((nconf)&&(nconf->com())) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); - nconf->com().serialize(outp); - outp.armor(peer->key(),true); - RR->node->putPacket(_remoteAddress,outp.data(),outp.size()); - } - } - } - } + if (network) + network->validateAndAddMembershipCertificate(com); } } diff --git a/node/Network.hpp b/node/Network.hpp index 53a22dcd..d7320d46 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -184,7 +184,7 @@ public: bool validateAndAddMembershipCertificate(const CertificateOfMembership &cert); /** - * Check if we should push membership certificate to a peer, and update last pushed + * Check if we should push membership certificate to a peer, AND update last pushed * * If we haven't pushed a cert to this peer in a long enough time, this returns * true and updates the last pushed time. Otherwise it returns false. diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 5809504a..46116c07 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -102,13 +102,9 @@ void OutboundMulticast::init( void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toAddr) { - SharedPtr network(RR->node->network(_nwid)); - - if (!network) - return; - if (_haveCom) { - if (network->peerNeedsOurMembershipCertificate(toAddr,RR->node->now())) { + SharedPtr network(RR->node->network(_nwid)); + if ((network)&&(network->peerNeedsOurMembershipCertificate(toAddr,RR->node->now()))) { _packetWithCom.newInitializationVector(); _packetWithCom.setDestination(toAddr); //TRACE(">>MC %.16llx -> %s (with COM)",(unsigned long long)this,toAddr.toString().c_str()); diff --git a/node/Packet.hpp b/node/Packet.hpp index 9787edb7..e84306c2 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -678,10 +678,10 @@ public: * <[...] serialized certificate of membership> * [ ... additional certificates may follow ...] * - * OK/ERROR are not generated, but the recipient should push its network - * membership certificate if the certificate the peer pushed is valid - * and agrees and if it hasn't done so in too long. This ensures instant - * network authentication setup between valid and authorized peers. + * This is sent in response to ERROR_NEED_MEMBERSHIP_CERTIFICATE and may + * be pushed at any other time to keep exchanged certificates up to date. + * + * OK/ERROR are not generated. */ VERB_NETWORK_MEMBERSHIP_CERTIFICATE = 10, diff --git a/node/Peer.cpp b/node/Peer.cpp index 7c936d4a..84aa8bef 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -208,12 +208,13 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) } } -void Peer::pushDirectPaths(const RuntimeEnvironment *RR,const std::vector &dps,uint64_t now,bool force) +void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force) { - if ((!dps.empty())&&(((now - _lastDirectPathPush) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force))) { + if ((((now - _lastDirectPathPush) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force))) { _lastDirectPathPush = now; - TRACE("pushing %u direct paths to %s",(unsigned int)dps.size(),_id.address().toString().c_str()); + std::vector dps(RR->node->directPaths()); + TRACE("pushing %u direct paths (local interface addresses) to %s",(unsigned int)dps.size(),_id.address().toString().c_str()); std::vector::const_iterator p(dps.begin()); while (p != dps.end()) { @@ -266,7 +267,8 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,const std::vector if (count) { outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); - RR->sw->send(outp,true,0); + outp.armor(_key,true); + path->send(RR,outp.data(),outp.size(),now); } } } diff --git a/node/Peer.hpp b/node/Peer.hpp index 2af3b9e6..f5118794 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -179,14 +179,14 @@ public: void doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now); /** - * Push direct paths (if within rate limit) + * Push direct paths if we haven't done so in [rate limit] milliseconds * * @param RR Runtime environment - * @param dps Direct paths to me to push to this peer + * @param path Remote path to use to send the push * @param now Current time - * @param force If true, force regardless of when we pushed direct paths last + * @param force If true, push regardless of rate limit */ - void pushDirectPaths(const RuntimeEnvironment *RR,const std::vector &dps,uint64_t now,bool force); + void pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force); /** * @return All known direct paths to this peer diff --git a/node/Switch.cpp b/node/Switch.cpp index 201f36d1..13070be1 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -162,38 +162,34 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c if (to[0] == MAC::firstOctetForNetwork(network->id())) { // Destination is another ZeroTier peer on the same network - Address toZT(to.toAddress(network->id())); - if (network->isAllowed(toZT)) { - const bool includeCom = network->peerNeedsOurMembershipCertificate(toZT,RR->node->now()); - if ((fromBridged)||(includeCom)) { - Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(network->id()); - if (includeCom) { - outp.append((unsigned char)0x01); // 0x01 -- COM included - nconf->com().serialize(outp); - } else { - outp.append((unsigned char)0x00); - } - to.appendTo(outp); - from.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(data,len); - outp.compress(); - send(outp,true,network->id()); + Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this + const bool includeCom = network->peerNeedsOurMembershipCertificate(toZT,RR->node->now()); + if ((fromBridged)||(includeCom)) { + Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME); + outp.append(network->id()); + if (includeCom) { + outp.append((unsigned char)0x01); // 0x01 -- COM included + nconf->com().serialize(outp); } else { - Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME); - outp.append(network->id()); - outp.append((uint16_t)etherType); - outp.append(data,len); - outp.compress(); - send(outp,true,network->id()); + outp.append((unsigned char)0x00); } - - //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d includeCom==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged,(int)includeCom); + to.appendTo(outp); + from.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(data,len); + outp.compress(); + send(outp,true,network->id()); } else { - TRACE("%.16llx: UNICAST: %s -> %s etherType==%s dropped, destination not a member of private network",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType)); + Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME); + outp.append(network->id()); + outp.append((uint16_t)etherType); + outp.append(data,len); + outp.compress(); + send(outp,true,network->id()); } + //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d includeCom==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged,(int)includeCom); + return; } @@ -205,7 +201,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c /* Create an array of up to ZT_MAX_BRIDGE_SPAM recipients for this bridged frame. */ bridges[0] = network->findBridgeTo(to); - if ((bridges[0])&&(bridges[0] != RR->identity.address())&&(network->isAllowed(bridges[0]))&&(network->permitsBridging(bridges[0]))) { + if ((bridges[0])&&(bridges[0] != RR->identity.address())&&(network->permitsBridging(bridges[0]))) { /* We have a known bridge route for this MAC, send it there. */ ++numBridges; } else if (!nconf->activeBridges().empty()) { @@ -215,8 +211,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c if (nconf->activeBridges().size() <= ZT_MAX_BRIDGE_SPAM) { // If there are <= ZT_MAX_BRIDGE_SPAM active bridges, spam them all while (ab != nconf->activeBridges().end()) { - if (network->isAllowed(*ab)) // config sanity check - bridges[numBridges++] = *ab; + bridges[numBridges++] = *ab; ++ab; } } else { @@ -225,8 +220,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c if (ab == nconf->activeBridges().end()) ab = nconf->activeBridges().begin(); if (((unsigned long)RR->prng->next32() % (unsigned long)nconf->activeBridges().size()) == 0) { - if (network->isAllowed(*ab)) // config sanity check - bridges[numBridges++] = *ab; + bridges[numBridges++] = *ab; ++ab; } else ++ab; } @@ -703,29 +697,28 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) if (peer) { const uint64_t now = RR->node->now(); + SharedPtr network; + SharedPtr nconf; if (nwid) { - // If this packet has an associated network, give the peer additional hints for direct connectivity - peer->pushDirectPaths(RR,RR->node->directPaths(),now,false); + network = RR->node->network(nwid); + if (!network) + return false; // we probably just left this network, let its packets die + nconf = network->config2(); + if (!nconf) + return false; // sanity check: unconfigured network? why are we trying to talk to it? } RemotePath *viaPath = peer->getBestPath(now); + SharedPtr relay; if (!viaPath) { - SharedPtr relay; - // See if this network has a preferred relay (if packet has an associated network) - if (nwid) { - SharedPtr network(RR->node->network(nwid)); - if (network) { - SharedPtr nconf(network->config2()); - if (nconf) { - unsigned int latency = ~((unsigned int)0); - for(std::vector< std::pair >::const_iterator r(nconf->relays().begin());r!=nconf->relays().end();++r) { - if (r->first != peer->address()) { - SharedPtr rp(RR->topology->getPeer(r->first)); - if ((rp)&&(rp->hasActiveDirectPath(now))&&(rp->latency() <= latency)) - rp.swap(relay); - } - } + if (nconf) { + unsigned int latency = ~((unsigned int)0); + for(std::vector< std::pair >::const_iterator r(nconf->relays().begin());r!=nconf->relays().end();++r) { + if (r->first != peer->address()) { + SharedPtr rp(RR->topology->getPeer(r->first)); + if ((rp)&&(rp->hasActiveDirectPath(now))&&(rp->latency() <= latency)) + rp.swap(relay); } } } @@ -735,7 +728,12 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) relay = RR->topology->getBestRoot(); if (!(relay)||(!(viaPath = relay->getBestPath(now)))) - return false; + return false; // no paths, no root servers? + } + + if ((network)&&(relay)&&(network->isAllowed(peer->address()))) { + // Push hints for direct connectivity to this peer if we are relaying + peer->pushDirectPaths(RR,viaPath,now,false); } Packet tmp(packet); diff --git a/node/Switch.hpp b/node/Switch.hpp index af6e5938..95ca362c 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -108,10 +108,13 @@ public: * * Needless to say, the packet's source must be this node. Otherwise it * won't be encrypted right. (This is not used for relaying.) + * + * The network ID should only be specified for frames and other actual + * network traffic. * * @param packet Packet to send * @param encrypt Encrypt packet payload? (always true except for HELLO) - * @param nwid Network ID or 0 if message is not related to a specific network + * @param nwid Related network ID or 0 if message is not in-network traffic */ void send(const Packet &packet,bool encrypt,uint64_t nwid); -- cgit v1.2.3 From 41fc08b3308be6ac57d737b225a58d41854bd695 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 7 Jul 2015 10:06:05 -0700 Subject: etherTypeName() is only used in Switch and only with ZT_TRACE --- node/Switch.cpp | 33 +++++++++++++++++---------------- node/Switch.hpp | 7 ------- 2 files changed, 17 insertions(+), 23 deletions(-) (limited to 'node/Switch.cpp') diff --git a/node/Switch.cpp b/node/Switch.cpp index 13070be1..62fa02cd 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -48,6 +48,23 @@ namespace ZeroTier { +#ifdef ZT_TRACE +static const char *etherTypeName(const unsigned int etherType) +{ + switch(etherType) { + case ZT_ETHERTYPE_IPV4: return "IPV4"; + case ZT_ETHERTYPE_ARP: return "ARP"; + case ZT_ETHERTYPE_RARP: return "RARP"; + case ZT_ETHERTYPE_ATALK: return "ATALK"; + case ZT_ETHERTYPE_AARP: return "AARP"; + case ZT_ETHERTYPE_IPX_A: return "IPX_A"; + case ZT_ETHERTYPE_IPX_B: return "IPX_B"; + case ZT_ETHERTYPE_IPV6: return "IPV6"; + } + return "UNKNOWN"; +} +#endif // ZT_TRACE + Switch::Switch(const RuntimeEnvironment *renv) : RR(renv) { @@ -519,22 +536,6 @@ unsigned long Switch::doTimerTasks(uint64_t now) return nextDelay; } -const char *Switch::etherTypeName(const unsigned int etherType) - throw() -{ - switch(etherType) { - case ZT_ETHERTYPE_IPV4: return "IPV4"; - case ZT_ETHERTYPE_ARP: return "ARP"; - case ZT_ETHERTYPE_RARP: return "RARP"; - case ZT_ETHERTYPE_ATALK: return "ATALK"; - case ZT_ETHERTYPE_AARP: return "AARP"; - case ZT_ETHERTYPE_IPX_A: return "IPX_A"; - case ZT_ETHERTYPE_IPX_B: return "IPX_B"; - case ZT_ETHERTYPE_IPV6: return "IPV6"; - } - return "UNKNOWN"; -} - void Switch::_handleRemotePacketFragment(const InetAddress &fromAddr,const void *data,unsigned int len) { Packet::Fragment fragment(data,len); diff --git a/node/Switch.hpp b/node/Switch.hpp index 1b29d050..89c9a56b 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -177,13 +177,6 @@ public: */ unsigned long doTimerTasks(uint64_t now); - /** - * @param etherType Ethernet type ID - * @return Human-readable name - */ - static const char *etherTypeName(const unsigned int etherType) - throw(); - private: void _handleRemotePacketFragment(const InetAddress &fromAddr,const void *data,unsigned int len); void _handleRemotePacketHead(const InetAddress &fromAddr,const void *data,unsigned int len); -- cgit v1.2.3 From 3f567a07ca0cda5c3370105d88cb939ad62b4b7d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 7 Jul 2015 10:49:50 -0700 Subject: Save a little bit of RAM by getting rid of overkill CMWC4096 non-crypto PRNG and replacing it with a simple non-crypto PRNG that just uses Salsa20. --- node/CMWC4096.hpp | 91 --------------------------------------------- node/Multicaster.cpp | 5 +-- node/Node.cpp | 22 +++++++++-- node/Node.hpp | 10 +++++ node/RuntimeEnvironment.hpp | 3 -- node/Switch.cpp | 5 +-- 6 files changed, 32 insertions(+), 104 deletions(-) delete mode 100644 node/CMWC4096.hpp (limited to 'node/Switch.cpp') diff --git a/node/CMWC4096.hpp b/node/CMWC4096.hpp deleted file mode 100644 index b62d7d67..00000000 --- a/node/CMWC4096.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_CMWC4096_HPP -#define ZT_CMWC4096_HPP - -#include -#include "Utils.hpp" - -namespace ZeroTier { - -/** - * Complement Multiply With Carry random number generator - * - * Based on original code posted to Usenet in the public domain by - * George Marsaglia. Period is approximately 2^131086. - * - * This is not used for cryptographic purposes but for a very fast - * and high-quality PRNG elsewhere in the code. - */ -class CMWC4096 -{ -public: - /** - * Construct and initialize from secure random source - */ - CMWC4096() - throw() - { - Utils::getSecureRandom(Q,sizeof(Q)); - Utils::getSecureRandom(&c,sizeof(c)); - c %= 809430660; - i = 4095; - } - - inline uint32_t next32() - throw() - { - uint32_t __i = ++i & 4095; - const uint64_t t = (18782ULL * (uint64_t)Q[__i]) + (uint64_t)c; - c = (uint32_t)(t >> 32); - uint32_t x = c + (uint32_t)t; - const uint32_t p = (uint32_t)(x < c); x += p; c += p; - return (Q[__i] = 0xfffffffe - x); - } - - inline uint64_t next64() - throw() - { - return ((((uint64_t)next32()) << 32) ^ (uint64_t)next32()); - } - - inline double nextDouble() - throw() - { - return ((double)(next32()) / 4294967296.0); - } - -private: - uint32_t Q[4096]; - uint32_t c; - uint32_t i; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 77ea2e66..3c105236 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -35,7 +35,6 @@ #include "Switch.hpp" #include "Packet.hpp" #include "Peer.hpp" -#include "CMWC4096.hpp" #include "C25519.hpp" #include "CertificateOfMembership.hpp" @@ -97,7 +96,7 @@ unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const // will return different subsets of a large multicast group. k = 0; while ((added < limit)&&(k < gs->second.members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_UDP_DEFAULT_PAYLOAD_MTU)) { - rptr = (unsigned int)RR->prng->next32(); + rptr = (unsigned int)RR->node->prng(); restart_member_scan: a = gs->second.members[rptr % (unsigned int)gs->second.members.size()].address.toInt(); @@ -171,7 +170,7 @@ void Multicaster::send( for(unsigned long i=0;i0;--i) { - unsigned long j = RR->prng->next32() % (i + 1); + unsigned long j = (unsigned long)RR->node->prng() % (i + 1); unsigned long tmp = indexes[j]; indexes[j] = indexes[i]; indexes[i] = tmp; diff --git a/node/Node.cpp b/node/Node.cpp index d8bd8910..3df34aec 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -37,7 +37,6 @@ #include "Node.hpp" #include "RuntimeEnvironment.hpp" #include "NetworkController.hpp" -#include "CMWC4096.hpp" #include "Switch.hpp" #include "Multicaster.hpp" #include "AntiRecursion.hpp" @@ -76,6 +75,7 @@ Node::Node( _eventCallback(eventCallback), _networks(), _networks_m(), + _prngStreamPtr(0), _now(now), _lastPingCheck(0), _lastHousekeepingRun(0) @@ -85,6 +85,15 @@ Node::Node( _newestVersionSeen[2] = ZEROTIER_ONE_VERSION_REVISION; _online = false; + // Use Salsa20 alone as a high-quality non-crypto PRNG + { + char foo[32]; + Utils::getSecureRandom(foo,32); + _prng.init(foo,256,foo,8); + memset(_prngStream,0,sizeof(_prngStream)); + _prng.encrypt(_prngStream,_prngStream,sizeof(_prngStream)); + } + std::string idtmp(dataStoreGet("identity.secret")); if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { TRACE("identity.secret not found, generating..."); @@ -103,7 +112,6 @@ Node::Node( } try { - RR->prng = new CMWC4096(); RR->sw = new Switch(RR); RR->mc = new Multicaster(RR); RR->antiRec = new AntiRecursion(); @@ -115,7 +123,6 @@ Node::Node( delete RR->antiRec; delete RR->mc; delete RR->sw; - delete RR->prng; throw; } @@ -146,7 +153,6 @@ Node::~Node() delete RR->antiRec; delete RR->mc; delete RR->sw; - delete RR->prng; } ZT1_ResultCode Node::processWirePacket( @@ -510,6 +516,14 @@ void Node::postTrace(const char *module,unsigned int line,const char *fmt,...) } #endif // ZT_TRACE +uint64_t Node::prng() +{ + unsigned int p = (++_prngStreamPtr % (sizeof(_prngStream) / sizeof(uint64_t))); + if (!p) + _prng.encrypt(_prngStream,_prngStream,sizeof(_prngStream)); + return _prngStream[p]; +} + } // namespace ZeroTier /****************************************************************************/ diff --git a/node/Node.hpp b/node/Node.hpp index fe31576c..579d3a57 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -44,6 +44,7 @@ #include "MAC.hpp" #include "Network.hpp" #include "Path.hpp" +#include "Salsa20.hpp" #undef TRACE #ifdef ZT_TRACE @@ -219,6 +220,11 @@ public: void postTrace(const char *module,unsigned int line,const char *fmt,...); #endif + /** + * @return Next 64-bit random number (not for cryptographic use) + */ + uint64_t prng(); + private: inline SharedPtr _network(uint64_t nwid) const { @@ -253,6 +259,10 @@ private: Mutex _backgroundTasksLock; + unsigned int _prngStreamPtr; + Salsa20 _prng; + uint64_t _prngStream[16]; // repeatedly encrypted with _prng to yield a high-quality non-crypto PRNG stream + uint64_t _now; uint64_t _lastPingCheck; uint64_t _lastHousekeepingRun; diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 228040e7..e5d1f446 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -38,7 +38,6 @@ namespace ZeroTier { class NodeConfig; class Switch; class Topology; -class CMWC4096; class Node; class Multicaster; class AntiRecursion; @@ -55,7 +54,6 @@ public: node(n), identity(), localNetworkController((NetworkController *)0), - prng((CMWC4096 *)0), sw((Switch *)0), mc((Multicaster *)0), antiRec((AntiRecursion *)0), @@ -83,7 +81,6 @@ public: * These are constant and never null after startup unless indicated. */ - CMWC4096 *prng; Switch *sw; Multicaster *mc; AntiRecursion *antiRec; diff --git a/node/Switch.cpp b/node/Switch.cpp index 62fa02cd..4fd5d769 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -42,7 +42,6 @@ #include "InetAddress.hpp" #include "Topology.hpp" #include "Peer.hpp" -#include "CMWC4096.hpp" #include "AntiRecursion.hpp" #include "Packet.hpp" @@ -236,7 +235,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c while (numBridges < ZT_MAX_BRIDGE_SPAM) { if (ab == nconf->activeBridges().end()) ab = nconf->activeBridges().begin(); - if (((unsigned long)RR->prng->next32() % (unsigned long)nconf->activeBridges().size()) == 0) { + if (((unsigned long)RR->node->prng() % (unsigned long)nconf->activeBridges().size()) == 0) { bridges[numBridges++] = *ab; ++ab; } else ++ab; @@ -327,7 +326,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force) * the order we make each attempted NAT-t favor one or the other going * first, meaning if it doesn't succeed the first time it might the second * and so forth. */ - unsigned int alt = RR->prng->next32() & 1; + unsigned int alt = (unsigned int)RR->node->prng() & 1; unsigned int completed = alt + 2; while (alt != completed) { if ((alt & 1) == 0) { -- cgit v1.2.3