summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
Diffstat (limited to 'node')
-rw-r--r--node/Constants.hpp9
-rw-r--r--node/IncomingPacket.cpp16
-rw-r--r--node/Node.cpp22
-rw-r--r--node/Node.hpp3
-rw-r--r--node/Path.hpp13
-rw-r--r--node/Peer.cpp6
-rw-r--r--node/Peer.hpp18
-rw-r--r--node/Switch.cpp31
8 files changed, 105 insertions, 13 deletions
diff --git a/node/Constants.hpp b/node/Constants.hpp
index afd2e4ec..b3c3dec0 100644
--- a/node/Constants.hpp
+++ b/node/Constants.hpp
@@ -351,6 +351,11 @@
#define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5
/**
+ * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6)
+ */
+#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4
+
+/**
* Time horizon for VERB_NETWORK_CREDENTIALS cutoff
*/
#define ZT_PEER_CREDENTIALS_CUTOFF_TIME 60000
@@ -366,9 +371,9 @@
#define ZT_PEER_GENERAL_RATE_LIMIT 1000
/**
- * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6)
+ * How long is a path or peer considered to have a trust relationship with us (for e.g. relay policy) since last trusted established packet?
*/
-#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4
+#define ZT_TRUST_EXPIRATION 600000
/**
* Enable support for older network configurations from older (pre-1.1.6) controllers
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index 64dccef3..9bc41d47 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -670,8 +670,14 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay
return true;
}
- } else if ( (to != network->mac()) && (!to.isMulticast()) ) {
- if (!network->config().permitsBridging(RR->identity.address())) {
+ } else if (to != network->mac()) {
+ if (to.isMulticast()) {
+ if (network->config().multicastLimit == 0) {
+ TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: network %.16llx does not allow multicast",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id());
+ peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay
+ return true;
+ }
+ } else if (!network->config().permitsBridging(RR->identity.address())) {
TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id());
peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay
return true;
@@ -1038,6 +1044,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
return true;
}
+ if (network->config().multicastLimit == 0) {
+ TRACE("dropped MULTICAST_FRAME from %s(%s): network %.16llx does not allow multicast",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id());
+ peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false);
+ return true;
+ }
+
unsigned int gatherLimit = 0;
if ((flags & 0x02) != 0) {
gatherLimit = at<uint32_t>(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT);
diff --git a/node/Node.cpp b/node/Node.cpp
index 59794854..51f1b5c0 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -71,7 +71,8 @@ Node::Node(
_prngStreamPtr(0),
_now(now),
_lastPingCheck(0),
- _lastHousekeepingRun(0)
+ _lastHousekeepingRun(0),
+ _relayPolicy(ZT_RELAY_POLICY_TRUSTED)
{
_online = false;
@@ -118,6 +119,9 @@ Node::Node(
throw;
}
+ if (RR->topology->amRoot())
+ _relayPolicy = ZT_RELAY_POLICY_ALWAYS;
+
postEvent(ZT_EVENT_UP);
}
@@ -131,6 +135,7 @@ Node::~Node()
delete RR->topology;
delete RR->mc;
delete RR->sw;
+
#ifdef ZT_ENABLE_CLUSTER
delete RR->cluster;
#endif
@@ -319,6 +324,12 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB
return ZT_RESULT_OK;
}
+ZT_ResultCode Node::setRelayPolicy(enum ZT_RelayPolicy rp)
+{
+ _relayPolicy = rp;
+ return ZT_RESULT_OK;
+}
+
ZT_ResultCode Node::join(uint64_t nwid,void *uptr)
{
Mutex::Lock _l(_networks_m);
@@ -824,6 +835,15 @@ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,vol
}
}
+enum ZT_ResultCode ZT_Node_setRelayPolicy(ZT_Node *node,enum ZT_RelayPolicy rp)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->setRelayPolicy(rp);
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr)
{
try {
diff --git a/node/Node.hpp b/node/Node.hpp
index 315b5248..56869816 100644
--- a/node/Node.hpp
+++ b/node/Node.hpp
@@ -91,6 +91,7 @@ public:
unsigned int frameLength,
volatile uint64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline);
+ ZT_ResultCode setRelayPolicy(enum ZT_RelayPolicy rp);
ZT_ResultCode join(uint64_t nwid,void *uptr);
ZT_ResultCode leave(uint64_t nwid,void **uptr);
ZT_ResultCode multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
@@ -245,6 +246,7 @@ public:
inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,nwid,nuptr,op,nc); }
inline bool online() const throw() { return _online; }
+ inline ZT_RelayPolicy relayPolicy() const { return _relayPolicy; }
#ifdef ZT_TRACE
void postTrace(const char *module,unsigned int line,const char *fmt,...);
@@ -326,6 +328,7 @@ private:
uint64_t _now;
uint64_t _lastPingCheck;
uint64_t _lastHousekeepingRun;
+ ZT_RelayPolicy _relayPolicy;
bool _online;
};
diff --git a/node/Path.hpp b/node/Path.hpp
index 27cff645..5993be69 100644
--- a/node/Path.hpp
+++ b/node/Path.hpp
@@ -104,6 +104,7 @@ public:
Path() :
_lastOut(0),
_lastIn(0),
+ _lastTrustEstablishedPacketReceived(0),
_addr(),
_localAddress(),
_ipScope(InetAddress::IP_SCOPE_NONE)
@@ -113,6 +114,7 @@ public:
Path(const InetAddress &localAddress,const InetAddress &addr) :
_lastOut(0),
_lastIn(0),
+ _lastTrustEstablishedPacketReceived(0),
_addr(addr),
_localAddress(localAddress),
_ipScope(addr.ipScope())
@@ -127,6 +129,11 @@ public:
inline void received(const uint64_t t) { _lastIn = t; }
/**
+ * Set time last trusted packet was received (done in Peer::received())
+ */
+ inline void trustedPacketReceived(const uint64_t t) { _lastTrustEstablishedPacketReceived = t; }
+
+ /**
* Send a packet via this path (last out time is also updated)
*
* @param RR Runtime environment
@@ -160,6 +167,11 @@ public:
inline InetAddress::IpScope ipScope() const { return _ipScope; }
/**
+ * @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms
+ */
+ inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); }
+
+ /**
* @return Preference rank, higher == better
*/
inline unsigned int preferenceRank() const
@@ -232,6 +244,7 @@ public:
private:
uint64_t _lastOut;
uint64_t _lastIn;
+ uint64_t _lastTrustEstablishedPacketReceived;
InetAddress _addr;
InetAddress _localAddress;
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
diff --git a/node/Peer.cpp b/node/Peer.cpp
index 560ca786..78af9063 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -52,6 +52,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
_lastEchoRequestReceived(0),
_lastComRequestReceived(0),
_lastCredentialsReceived(0),
+ _lastTrustEstablishedPacketReceived(0),
RR(renv),
_remoteClusterOptimal4(0),
_vProto(0),
@@ -132,6 +133,11 @@ void Peer::received(
else if (verb == Packet::VERB_MULTICAST_FRAME)
_lastMulticastFrame = now;
+ if (trustEstablished) {
+ _lastTrustEstablishedPacketReceived = now;
+ path->trustedPacketReceived(now);
+ }
+
if (hops == 0) {
bool pathIsConfirmed = false;
{
diff --git a/node/Peer.hpp b/node/Peer.hpp
index 5382e3f0..1ae239bc 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -312,7 +312,7 @@ public:
/**
* @return 256-bit secret symmetric encryption key
*/
- inline const unsigned char *key() const throw() { return _key; }
+ inline const unsigned char *key() const { return _key; }
/**
* Set the currently known remote version of this peer's client
@@ -330,12 +330,17 @@ public:
_vRevision = (uint16_t)vrev;
}
- inline unsigned int remoteVersionProtocol() const throw() { return _vProto; }
- inline unsigned int remoteVersionMajor() const throw() { return _vMajor; }
- inline unsigned int remoteVersionMinor() const throw() { return _vMinor; }
- inline unsigned int remoteVersionRevision() const throw() { return _vRevision; }
+ inline unsigned int remoteVersionProtocol() const { return _vProto; }
+ inline unsigned int remoteVersionMajor() const { return _vMajor; }
+ inline unsigned int remoteVersionMinor() const { return _vMinor; }
+ inline unsigned int remoteVersionRevision() const { return _vRevision; }
- inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
+ inline bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
+
+ /**
+ * @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms
+ */
+ inline bool trustEstablished(const uint64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); }
/**
* Rate limit gate for VERB_PUSH_DIRECT_PATHS
@@ -470,6 +475,7 @@ private:
uint64_t _lastEchoRequestReceived;
uint64_t _lastComRequestReceived;
uint64_t _lastCredentialsReceived;
+ uint64_t _lastTrustEstablishedPacketReceived;
const RuntimeEnvironment *RR;
uint32_t _remoteClusterOptimal4;
uint16_t _vProto;
diff --git a/node/Switch.cpp b/node/Switch.cpp
index ea92c99a..beb36b6c 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -105,7 +105,18 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from
const Address destination(fragment.destination());
if (destination != RR->identity.address()) {
- // Fragment is not for us, so try to relay it
+ switch(RR->node->relayPolicy()) {
+ case ZT_RELAY_POLICY_ALWAYS:
+ break;
+ case ZT_RELAY_POLICY_TRUSTED:
+ if (!path->trustEstablished(now))
+ return;
+ break;
+ // case ZT_RELAY_POLICY_NEVER:
+ default:
+ return;
+ }
+
if (fragment.hops() < ZT_RELAY_MAX_HOPS) {
fragment.incrementHops();
@@ -203,9 +214,20 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from
//TRACE("<< %.16llx %s -> %s (size: %u)",(unsigned long long)packet->packetId(),source.toString().c_str(),destination.toString().c_str(),packet->size());
if (destination != RR->identity.address()) {
+ switch(RR->node->relayPolicy()) {
+ case ZT_RELAY_POLICY_ALWAYS:
+ break;
+ case ZT_RELAY_POLICY_TRUSTED:
+ if (!path->trustEstablished(now))
+ return;
+ break;
+ // case ZT_RELAY_POLICY_NEVER:
+ default:
+ return;
+ }
+
Packet packet(data,len);
- // Packet is not for us, so try to relay it
if (packet.hops() < ZT_RELAY_MAX_HOPS) {
packet.incrementHops();
@@ -327,6 +349,11 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
}
if (to.isMulticast()) {
+ if (network->config().multicastLimit == 0) {
+ TRACE("%.16llx: dropped multicast: not allowed on network",network->id());
+ return;
+ }
+
// Destination is a multicast address (including broadcast)
MulticastGroup mg(to,0);