Implement relay policy, and setting multicast limit to 0 now disables multicast on the network as would be expected.

This commit is contained in:
Adam Ierymenko 2016-09-13 14:27:18 -07:00
parent ced8dfc639
commit 5b6d27e659
12 changed files with 159 additions and 83 deletions

View File

@ -870,19 +870,28 @@ enum ZT_VirtualNetworkConfigOperation
ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4
};
enum ZT_RelayPolicy
{
ZT_RELAY_POLICY_NEVER = 0,
ZT_RELAY_POLICY_TRUSTED = 1,
ZT_RELAY_POLICY_ALWAYS = 2
};
/**
* What trust hierarchy role does this peer have?
*/
enum ZT_PeerRole {
enum ZT_PeerRole
{
ZT_PEER_ROLE_LEAF = 0, // ordinary node
ZT_PEER_ROLE_RELAY = 1, // relay node
ZT_PEER_ROLE_ROOT = 2 // root server
ZT_PEER_ROLE_UPSTREAM = 1, // upstream node
ZT_PEER_ROLE_ROOT = 2 // global root
};
/**
* Vendor ID
*/
enum ZT_Vendor {
enum ZT_Vendor
{
ZT_VENDOR_UNSPECIFIED = 0,
ZT_VENDOR_ZEROTIER = 1
};
@ -890,7 +899,8 @@ enum ZT_Vendor {
/**
* Platform type
*/
enum ZT_Platform {
enum ZT_Platform
{
ZT_PLATFORM_UNSPECIFIED = 0,
ZT_PLATFORM_LINUX = 1,
ZT_PLATFORM_WINDOWS = 2,
@ -905,13 +915,15 @@ enum ZT_Platform {
ZT_PLATFORM_VXWORKS = 11,
ZT_PLATFORM_FREERTOS = 12,
ZT_PLATFORM_SYSBIOS = 13,
ZT_PLATFORM_HURD = 14
ZT_PLATFORM_HURD = 14,
ZT_PLATFORM_WEB = 15
};
/**
* Architecture type
*/
enum ZT_Architecture {
enum ZT_Architecture
{
ZT_ARCHITECTURE_UNSPECIFIED = 0,
ZT_ARCHITECTURE_X86 = 1,
ZT_ARCHITECTURE_X64 = 2,
@ -926,7 +938,8 @@ enum ZT_Architecture {
ZT_ARCHITECTURE_SPARC32 = 11,
ZT_ARCHITECTURE_SPARC64 = 12,
ZT_ARCHITECTURE_DOTNET_CLR = 13,
ZT_ARCHITECTURE_JAVA_JVM = 14
ZT_ARCHITECTURE_JAVA_JVM = 14,
ZT_ARCHITECTURE_WEB = 15
};
/**
@ -1681,6 +1694,15 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
*/
enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline);
/**
* Set node's relay policy
*
* @param node Node instance
* @param rp New relay policy
* @return OK(0) or error code
*/
enum ZT_ResultCode ZT_Node_setRelayPolicy(ZT_Node *node,enum ZT_RelayPolicy rp);
/**
* Join a network
*

View File

@ -350,6 +350,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
*/
@ -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

View File

@ -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);

View File

@ -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 {

View File

@ -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;
};

View File

@ -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())
@ -126,6 +128,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)
*
@ -159,6 +166,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
*/
@ -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

View File

@ -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;
{

View File

@ -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;

View File

@ -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);

View File

@ -436,12 +436,12 @@ bool ManagedRoute::sync()
}
if (!_applied.count(leftt)) {
_applied.insert(leftt);
_applied[rightt] = false; // not ifscoped
_routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
_routeCmd("change",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
}
if ((rightt)&&(!_applied.count(rightt))) {
_applied.insert(rightt);
_applied[rightt] = false; // not ifscoped
_routeCmd("add",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
_routeCmd("change",rightt,_via,(const char *)0,(_via) ? (const char *)0 : _device);
}
@ -457,7 +457,7 @@ bool ManagedRoute::sync()
}
} else {
if (!_applied.count(_target)) {
_applied.insert(_target);
_applied[_target] = true; // ifscoped
_routeCmd("add",_target,_via,_device,(_via) ? (const char *)0 : _device);
_routeCmd("change",_target,_via,_device,(_via) ? (const char *)0 : _device);
}
@ -468,65 +468,27 @@ bool ManagedRoute::sync()
#ifdef __LINUX__ // ----------------------------------------------------------
//if (needBifurcation) {
if (!_applied.count(leftt)) {
_applied.insert(leftt);
_routeCmd("replace",leftt,_via,(_via) ? (const char *)0 : _device);
}
if ((rightt)&&(!_applied.count(rightt))) {
_applied.insert(rightt);
_routeCmd("replace",rightt,_via,(_via) ? (const char *)0 : _device);
}
/*if (_applied.count(_target)) {
_applied.erase(_target);
_routeCmd("del",_target,_via,(_via) ? (const char *)0 : _device);
}*/
/*} else {
if (_applied.count(leftt)) {
_applied.erase(leftt);
_routeCmd("del",leftt,_via,(_via) ? (const char *)0 : _device);
}
if ((rightt)&&(_applied.count(rightt))) {
_applied.erase(rightt);
_routeCmd("del",rightt,_via,(_via) ? (const char *)0 : _device);
}
if (!_applied.count(_target)) {
_applied.insert(_target);
_routeCmd("replace",_target,_via,(_via) ? (const char *)0 : _device);
}
}*/
if (!_applied.count(leftt)) {
_applied[leftt] = false; // boolean unused
_routeCmd("replace",leftt,_via,(_via) ? (const char *)0 : _device);
}
if ((rightt)&&(!_applied.count(rightt))) {
_applied[rightt] = false; // boolean unused
_routeCmd("replace",rightt,_via,(_via) ? (const char *)0 : _device);
}
#endif // __LINUX__ ----------------------------------------------------------
#ifdef __WINDOWS__ // --------------------------------------------------------
//if (needBifurcation) {
if (!_applied.count(leftt)) {
_applied.insert(leftt);
_winRoute(false,interfaceLuid,interfaceIndex,leftt,_via);
}
if ((rightt)&&(!_applied.count(rightt))) {
_applied.insert(rightt);
_winRoute(false,interfaceLuid,interfaceIndex,rightt,_via);
}
/*if (_applied.count(_target)) {
_applied.erase(_target);
_winRoute(true,interfaceLuid,interfaceIndex,_target,_via);
}*/
/*} else {
if (_applied.count(leftt)) {
_applied.erase(leftt);
_winRoute(true,interfaceLuid,interfaceIndex,leftt,_via);
}
if ((rightt)&&(_applied.count(rightt))) {
_applied.erase(rightt);
_winRoute(true,interfaceLuid,interfaceIndex,rightt,_via);
}
if (!_applied.count(_target)) {
_applied.insert(_target);
_winRoute(false,interfaceLuid,interfaceIndex,_target,_via);
}
}*/
if (!_applied.count(leftt)) {
_applied[leftt] = false; // boolean unused
_winRoute(false,interfaceLuid,interfaceIndex,leftt,_via);
}
if ((rightt)&&(!_applied.count(rightt))) {
_applied[rightt] = false; // boolean unused
_winRoute(false,interfaceLuid,interfaceIndex,rightt,_via);
}
#endif // __WINDOWS__ --------------------------------------------------------
@ -553,9 +515,9 @@ void ManagedRoute::remove()
}
#endif // __BSD__ ------------------------------------------------------------
for(std::set<InetAddress>::iterator r(_applied.begin());r!=_applied.end();++r) {
for(std::map<InetAddress,bool>::iterator r(_applied.begin());r!=_applied.end();++r) {
#ifdef __BSD__ // ------------------------------------------------------------
_routeCmd("delete",*r,_via,(const char *)0,(_via) ? (const char *)0 : _device);
_routeCmd("delete",r->first,_via,r->second ? _device : (const char *)0,(_via) ? (const char *)0 : _device);
#endif // __BSD__ ------------------------------------------------------------
#ifdef __LINUX__ // ----------------------------------------------------------

View File

@ -9,7 +9,7 @@
#include <stdexcept>
#include <vector>
#include <set>
#include <map>
namespace ZeroTier {
@ -105,7 +105,7 @@ private:
InetAddress _target;
InetAddress _via;
InetAddress _systemVia; // for route overrides
std::set<InetAddress> _applied; // routes currently applied
std::map<InetAddress,bool> _applied; // routes currently applied
char _device[128];
char _systemDevice[128]; // for route overrides
};

View File

@ -215,7 +215,7 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT_Peer *peer)
const char *prole = "";
switch(peer->role) {
case ZT_PEER_ROLE_LEAF: prole = "LEAF"; break;
case ZT_PEER_ROLE_RELAY: prole = "RELAY"; break;
case ZT_PEER_ROLE_UPSTREAM: prole = "UPSTREAM"; break;
case ZT_PEER_ROLE_ROOT: prole = "ROOT"; break;
}