summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/ZeroTierOne.h45
-rw-r--r--node/IncomingPacket.cpp10
-rw-r--r--node/InetAddress.cpp24
-rw-r--r--node/InetAddress.hpp8
-rw-r--r--node/Node.cpp26
-rw-r--r--node/Node.hpp9
-rw-r--r--node/Peer.cpp2
-rw-r--r--service/OneService.cpp20
8 files changed, 131 insertions, 13 deletions
diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h
index 39959221..e087904f 100644
--- a/include/ZeroTierOne.h
+++ b/include/ZeroTierOne.h
@@ -1097,13 +1097,42 @@ typedef int (*ZT_DataStorePutFunction)(
* delivery. It only means that the packet appears to have been sent.
*/
typedef int (*ZT_WirePacketSendFunction)(
- ZT_Node *, /* Node */
- void *, /* User ptr */
- const struct sockaddr_storage *, /* Local address */
- const struct sockaddr_storage *, /* Remote address */
- const void *, /* Packet data */
- unsigned int, /* Packet length */
- unsigned int); /* TTL or 0 to use default */
+ ZT_Node *, /* Node */
+ void *, /* User ptr */
+ const struct sockaddr_storage *, /* Local address */
+ const struct sockaddr_storage *, /* Remote address */
+ const void *, /* Packet data */
+ unsigned int, /* Packet length */
+ unsigned int); /* TTL or 0 to use default */
+
+/**
+ * Function to check whether a path should be used for ZeroTier traffic
+ *
+ * Paramters:
+ * (1) Node
+ * (2) User pointer
+ * (3) Local interface address
+ * (4) Remote address
+ *
+ * This function must return nonzero (true) if the path should be used.
+ *
+ * If no path check function is specified, ZeroTier will still exclude paths
+ * that overlap with ZeroTier-assigned and managed IP address blocks. But the
+ * use of a path check function is recommended to ensure that recursion does
+ * not occur in cases where addresses are assigned by the OS or managed by
+ * an out of band mechanism like DHCP. The path check function should examine
+ * all configured ZeroTier interfaces and check to ensure that the supplied
+ * addresses will not result in ZeroTier traffic being sent over a ZeroTier
+ * interface (recursion).
+ *
+ * Obviously this is not required in configurations where this can't happen,
+ * such as network containers or embedded.
+ */
+typedef int (*ZT_PathCheckFunction)(
+ ZT_Node *, /* Node */
+ void *, /* User ptr */
+ const struct sockaddr_storage *, /* Local address */
+ const struct sockaddr_storage *); /* Remote address */
/****************************************************************************/
/* C Node API */
@@ -1121,6 +1150,7 @@ typedef int (*ZT_WirePacketSendFunction)(
* @param dataStoreGetFunction Function called to get objects from persistent storage
* @param dataStorePutFunction Function called to put objects in persistent storage
* @param virtualNetworkConfigFunction Function to be called when virtual LANs are created, deleted, or their config parameters change
+ * @param pathCheckFunction A function to check whether a path should be used for ZeroTier traffic, or NULL to allow any path
* @param eventCallback Function to receive status updates and non-fatal error notices
* @return OK (0) or error code if a fatal error condition has occurred
*/
@@ -1133,6 +1163,7 @@ enum ZT_ResultCode ZT_Node_new(
ZT_WirePacketSendFunction wirePacketSendFunction,
ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction,
ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction,
+ ZT_PathCheckFunction pathCheckFunction,
ZT_EventCallback eventCallback);
/**
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index 5c9279dd..c63d70b7 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -507,10 +507,12 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<
const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP);
+
InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
- peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP);
- RR->sw->rendezvous(withPeer,_localAddress,atAddr);
+ if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr))
+ RR->sw->rendezvous(withPeer,_localAddress,atAddr);
} else {
TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
}
@@ -941,7 +943,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
switch(addrType) {
case 4: {
InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4));
- if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) && (!peer->hasActivePathTo(now,a)) ) {
+ if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) && (!peer->hasActivePathTo(now,a)) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) {
if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
peer->sendHELLO(_localAddress,a,now);
@@ -952,7 +954,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
} break;
case 6: {
InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16));
- if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) && (!peer->hasActivePathTo(now,a)) ) {
+ if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) && (!peer->hasActivePathTo(now,a)) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) {
if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
peer->sendHELLO(_localAddress,a,now);
diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp
index f35eb9c3..1b3a8064 100644
--- a/node/InetAddress.cpp
+++ b/node/InetAddress.cpp
@@ -280,6 +280,30 @@ InetAddress InetAddress::network() const
return r;
}
+bool InetAddress::containsAddress(const InetAddress &addr) const
+{
+ if (addr.ss_family == ss_family) {
+ switch(ss_family) {
+ case AF_INET: {
+ const unsigned int bits = netmaskBits();
+ return ( (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) >> (32 - bits)) );
+ }
+ case AF_INET6: {
+ const InetAddress mask(netmask());
+ const uint8_t *m = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&mask)->sin6_addr.s6_addr);
+ const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_addr.s6_addr);
+ const uint8_t *b = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
+ for(unsigned int i=0;i<16;++i) {
+ if ((a[i] & m[i]) != b[i])
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
bool InetAddress::isNetwork() const
throw()
{
diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp
index 2573e694..201271f7 100644
--- a/node/InetAddress.hpp
+++ b/node/InetAddress.hpp
@@ -326,6 +326,14 @@ struct InetAddress : public sockaddr_storage
InetAddress network() const;
/**
+ * Test whether this IP/netmask contains this address
+ *
+ * @param addr Address to check
+ * @return True if this IP/netmask (route) contains this address
+ */
+ bool containsAddress(const InetAddress &addr) const;
+
+ /**
* @return True if this is an IPv4 address
*/
inline bool isV4() const throw() { return (ss_family == AF_INET); }
diff --git a/node/Node.cpp b/node/Node.cpp
index 19675bb5..f65aa843 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -64,6 +64,7 @@ Node::Node(
ZT_WirePacketSendFunction wirePacketSendFunction,
ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction,
ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction,
+ ZT_PathCheckFunction pathCheckFunction,
ZT_EventCallback eventCallback) :
_RR(this),
RR(&_RR),
@@ -73,6 +74,7 @@ Node::Node(
_wirePacketSendFunction(wirePacketSendFunction),
_virtualNetworkFrameFunction(virtualNetworkFrameFunction),
_virtualNetworkConfigFunction(virtualNetworkConfigFunction),
+ _pathCheckFunction(pathCheckFunction),
_eventCallback(eventCallback),
_networks(),
_networks_m(),
@@ -671,6 +673,27 @@ std::string Node::dataStoreGet(const char *name)
return r;
}
+bool Node::shouldUsePathForZeroTierTraffic(const InetAddress &localAddress,const InetAddress &remoteAddress)
+{
+ {
+ Mutex::Lock _l(_networks_m);
+ for(std::vector< std::pair< uint64_t, SharedPtr<Network> > >::const_iterator i=_networks.begin();i!=_networks.end();++i) {
+ SharedPtr<NetworkConfig> nc(i->second->config2());
+ if (nc) {
+ for(std::vector<InetAddress>::const_iterator a(nc->staticIps().begin());a!=nc->staticIps().end();++a) {
+ if (a->containsAddress(remoteAddress)) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ if (_pathCheckFunction)
+ return (_pathCheckFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,reinterpret_cast<const struct sockaddr_storage *>(&localAddress),reinterpret_cast<const struct sockaddr_storage *>(&remoteAddress)) != 0);
+ else return true;
+}
+
#ifdef ZT_TRACE
void Node::postTrace(const char *module,unsigned int line,const char *fmt,...)
{
@@ -743,11 +766,12 @@ enum ZT_ResultCode ZT_Node_new(
ZT_WirePacketSendFunction wirePacketSendFunction,
ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction,
ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction,
+ ZT_PathCheckFunction pathCheckFunction,
ZT_EventCallback eventCallback)
{
*node = (ZT_Node *)0;
try {
- *node = reinterpret_cast<ZT_Node *>(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,eventCallback));
+ *node = reinterpret_cast<ZT_Node *>(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,pathCheckFunction,eventCallback));
return ZT_RESULT_OK;
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
diff --git a/node/Node.hpp b/node/Node.hpp
index 15295139..b6b32363 100644
--- a/node/Node.hpp
+++ b/node/Node.hpp
@@ -71,6 +71,7 @@ public:
ZT_WirePacketSendFunction wirePacketSendFunction,
ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction,
ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction,
+ ZT_PathCheckFunction pathCheckFunction,
ZT_EventCallback eventCallback);
~Node();
@@ -189,6 +190,13 @@ public:
len);
}
+ /**
+ * @param localAddress Local address
+ * @param remoteAddress Remote address
+ * @return True if path should be used
+ */
+ bool shouldUsePathForZeroTierTraffic(const InetAddress &localAddress,const InetAddress &remoteAddress);
+
inline SharedPtr<Network> network(uint64_t nwid) const
{
Mutex::Lock _l(_networks_m);
@@ -288,6 +296,7 @@ private:
ZT_WirePacketSendFunction _wirePacketSendFunction;
ZT_VirtualNetworkFrameFunction _virtualNetworkFrameFunction;
ZT_VirtualNetworkConfigFunction _virtualNetworkConfigFunction;
+ ZT_PathCheckFunction _pathCheckFunction;
ZT_EventCallback _eventCallback;
std::vector< std::pair< uint64_t, SharedPtr<Network> > > _networks;
diff --git a/node/Peer.cpp b/node/Peer.cpp
index 04e5bdf0..c75a3e46 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -156,7 +156,7 @@ void Peer::received(
}
}
- if (!pathIsConfirmed) {
+ if ((!pathIsConfirmed)&&(RR->node->shouldUsePathForZeroTierTraffic(localAddr,remoteAddr))) {
if (verb == Packet::VERB_OK) {
Path *slot = (Path *)0;
diff --git a/service/OneService.cpp b/service/OneService.cpp
index 57e1718d..84ebdd87 100644
--- a/service/OneService.cpp
+++ b/service/OneService.cpp
@@ -397,6 +397,7 @@ static long SnodeDataStoreGetFunction(ZT_Node *node,void *uptr,const char *name,
static int SnodeDataStorePutFunction(ZT_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure);
static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl);
static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
+static int SnodePathCheckFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr);
#ifdef ZT_ENABLE_CLUSTER
static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len);
@@ -592,6 +593,7 @@ public:
SnodeWirePacketSendFunction,
SnodeVirtualNetworkFrameFunction,
SnodeVirtualNetworkConfigFunction,
+ SnodePathCheckFunction,
SnodeEventCallback);
#ifdef ZT_USE_MINIUPNPC
@@ -1393,6 +1395,22 @@ public:
t->second->put(MAC(sourceMac),MAC(destMac),etherType,data,len);
}
+ inline int nodePathCheckFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr)
+ {
+ Mutex::Lock _l(_taps_m);
+ for(std::map< uint64_t,EthernetTap * >::const_iterator t(_taps.begin());t!=_taps.end();++t) {
+ if (t->second) {
+ std::vector<InetAddress> ips(t->second->ips());
+ for(std::vector<InetAddress>::const_iterator i(ips.begin());i!=ips.end();++i) {
+ if (i->containsAddress(*(reinterpret_cast<const InetAddress *>(remoteAddr)))) {
+ return 0;
+ }
+ }
+ }
+ }
+ return 1;
+ }
+
inline void tapFrameHandler(uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
{
_node->processVirtualNetworkFrame(OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&_nextBackgroundTaskDeadline);
@@ -1527,6 +1545,8 @@ static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,const struct soc
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeWirePacketSendFunction(localAddr,addr,data,len,ttl); }
static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
{ reinterpret_cast<OneServiceImpl *>(uptr)->nodeVirtualNetworkFrameFunction(nwid,sourceMac,destMac,etherType,vlanId,data,len); }
+static int SnodePathCheckFunction(ZT_Node *node,void *uptr,const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr)
+{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodePathCheckFunction(localAddr,remoteAddr); }
#ifdef ZT_ENABLE_CLUSTER
static void SclusterSendFunction(void *uptr,unsigned int toMemberId,const void *data,unsigned int len)