Remove somewhat ugly and costly anti-recursion hack -- we will switch to more explicit methods.

This commit is contained in:
Adam Ierymenko 2016-01-11 09:06:10 -08:00
parent a56fbc1929
commit 1023ef23b7
7 changed files with 0 additions and 175 deletions

View File

@ -1,135 +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 <http://www.gnu.org/licenses/>.
*
* --
*
* 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_ANTIRECURSION_HPP
#define ZT_ANTIRECURSION_HPP
#include <string.h>
#include <stdlib.h>
#include "Constants.hpp"
namespace ZeroTier {
/**
* Size of anti-recursion history
*/
#define ZT_ANTIRECURSION_HISTORY_SIZE 16
/**
* Filter to prevent recursion (ZeroTier-over-ZeroTier)
*
* This works by logging ZeroTier packets that we send. It's then invoked
* again against packets read from local Ethernet taps. If the last 32
* bytes representing the ZeroTier packet match in the tap frame, then
* the frame is a re-injection of a frame that we sent and is rejected.
*
* This means that ZeroTier packets simply will not traverse ZeroTier
* networks, which would cause all sorts of weird problems.
*
* This is highly optimized code since it's checked for every packet.
*/
class AntiRecursion
{
public:
AntiRecursion()
{
for(int i=0;i<ZT_ANTIRECURSION_HISTORY_SIZE;++i) {
_history[i].tail[0] = 0;
_history[i].tail[1] = 0;
_history[i].tail[2] = 0;
_history[i].tail[3] = 0;
}
_ptr = 0;
}
/**
* Add an outgoing ZeroTier packet to the circular log
*
* @param data ZT packet data
* @param len Length of packet
*/
inline void logOutgoingZT(const void *const data,const unsigned int len)
{
if (len < 32)
return;
#ifdef ZT_NO_TYPE_PUNNING
memcpy(_history[++_ptr % ZT_ANTIRECURSION_HISTORY_SIZE].tail,reinterpret_cast<const uint8_t *>(data) + (len - 32),32);
#else
uint64_t *t = _history[++_ptr % ZT_ANTIRECURSION_HISTORY_SIZE].tail;
const uint64_t *p = reinterpret_cast<const uint64_t *>(reinterpret_cast<const uint8_t *>(data) + (len - 32));
*(t++) = *(p++);
*(t++) = *(p++);
*(t++) = *(p++);
*t = *p;
#endif
}
/**
* Check an ethernet frame from a local tap against anti-recursion history
*
* @param data Raw frame data
* @param len Length of frame
* @return True if frame is OK to be passed, false if it's a ZT frame that we sent
*/
inline bool checkEthernetFrame(const void *const data,const unsigned int len) const
{
if (len < 32)
return true;
const uint8_t *const pp = reinterpret_cast<const uint8_t *>(data) + (len - 32);
const _ArItem *i = _history;
const _ArItem *const end = i + ZT_ANTIRECURSION_HISTORY_SIZE;
while (i != end) {
#ifdef ZT_NO_TYPE_PUNNING
if (!memcmp(pp,i->tail,32)) {
return false;
}
#else
const uint64_t *t = i->tail;
const uint64_t *p = reinterpret_cast<const uint64_t *>(pp);
uint64_t bits = *(t++) ^ *(p++);
bits |= *(t++) ^ *(p++);
bits |= *(t++) ^ *(p++);
bits |= *t ^ *p;
if (!bits) {
return false;
}
#endif
++i;
}
return true;
}
private:
struct _ArItem { uint64_t tail[4]; };
_ArItem _history[ZT_ANTIRECURSION_HISTORY_SIZE];
volatile unsigned long _ptr;
};
} // namespace ZeroTier
#endif

View File

@ -45,7 +45,6 @@
#include "World.hpp"
#include "Cluster.hpp"
#include "Node.hpp"
#include "AntiRecursion.hpp"
#include "DeferredPackets.hpp"
namespace ZeroTier {
@ -163,7 +162,6 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE);
nconf->com().serialize(outp);
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
}
@ -250,7 +248,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer
outp.append((uint64_t)pid);
outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION);
outp.armor(key,true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
} else {
TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str());
@ -346,7 +343,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer
}
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version
@ -484,7 +480,6 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer>
outp.append(packetId());
queried.serialize(outp,false);
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
} else {
#ifdef ZT_ENABLE_CLUSTER
@ -645,7 +640,6 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer>
if (size() > ZT_PACKET_IDX_PAYLOAD)
outp.append(reinterpret_cast<const unsigned char *>(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD);
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP);
} catch ( ... ) {
@ -723,7 +717,6 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) { // sanity check
TRACE("NETWORK_CONFIG_REQUEST failed: internal error: netconf size %u is too large",(unsigned int)netconfStr.length());
} else {
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
}
@ -736,7 +729,6 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND);
outp.append(nwid);
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
} break;
@ -747,7 +739,6 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_);
outp.append(nwid);
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
} break;
@ -770,7 +761,6 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION);
outp.append(nwid);
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
} catch ( ... ) {
@ -816,7 +806,6 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar
const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit);
if (gatheredLocally) {
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
@ -910,7 +899,6 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
outp.append((unsigned char)0x02); // flag 0x02 = contains gather results
if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) {
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
}
@ -1221,7 +1209,6 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const
outp.append((uint16_t)sizeof(result));
outp.append(result,sizeof(result));
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
} else {
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
@ -1229,7 +1216,6 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const
outp.append(pid);
outp.append((unsigned char)Packet::ERROR_INVALID_REQUEST);
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
} break;
@ -1335,7 +1321,6 @@ void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,cons
outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
outp.append(nwid);
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}

View File

@ -39,7 +39,6 @@
#include "NetworkController.hpp"
#include "Switch.hpp"
#include "Multicaster.hpp"
#include "AntiRecursion.hpp"
#include "Topology.hpp"
#include "Buffer.hpp"
#include "Packet.hpp"
@ -114,7 +113,6 @@ Node::Node(
try {
RR->sw = new Switch(RR);
RR->mc = new Multicaster(RR);
RR->antiRec = new AntiRecursion();
RR->topology = new Topology(RR);
RR->sa = new SelfAwareness(RR);
RR->dp = new DeferredPackets(RR);
@ -122,7 +120,6 @@ Node::Node(
delete RR->dp;
delete RR->sa;
delete RR->topology;
delete RR->antiRec;
delete RR->mc;
delete RR->sw;
throw;
@ -141,7 +138,6 @@ Node::~Node()
delete RR->dp;
delete RR->sa;
delete RR->topology;
delete RR->antiRec;
delete RR->mc;
delete RR->sw;
#ifdef ZT_ENABLE_CLUSTER

View File

@ -26,7 +26,6 @@
*/
#include "Path.hpp"
#include "AntiRecursion.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp"
@ -34,7 +33,6 @@ namespace ZeroTier {
bool Path::send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now)
{
RR->antiRec->logOutgoingZT(data,len);
if (RR->node->putPacket(_localAddress,address(),data,len)) {
sent(now);
return true;

View File

@ -32,7 +32,6 @@
#include "Node.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "AntiRecursion.hpp"
#include "SelfAwareness.hpp"
#include "Cluster.hpp"
#include "Packet.hpp"
@ -104,7 +103,6 @@ void Peer::received(
}
outp.append((uint16_t)redirectTo.port());
outp.armor(_key,true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size());
} else {
// For older peers we use RENDEZVOUS to coax them into contacting us elsewhere.
@ -120,7 +118,6 @@ void Peer::received(
outp.append(redirectTo.rawIpData(),16);
}
outp.armor(_key,true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size());
}
suboptimalPath = true;
@ -199,7 +196,6 @@ void Peer::received(
// 1.1.1 and newer nodes support ECHO, which is smaller -- but 1.1.0 has a bug so use HELLO there too
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
outp.armor(_key,true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size());
} else {
sendHELLO(localAddr,remoteAddr,now);
@ -233,7 +229,6 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u
outp.append((uint64_t)RR->topology->worldTimestamp());
outp.armor(_key,false); // HELLO is sent in the clear
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size(),ttl);
}

View File

@ -41,7 +41,6 @@ class Switch;
class Topology;
class Node;
class Multicaster;
class AntiRecursion;
class NetworkController;
class SelfAwareness;
class Cluster;
@ -59,7 +58,6 @@ public:
,localNetworkController((NetworkController *)0)
,sw((Switch *)0)
,mc((Multicaster *)0)
,antiRec((AntiRecursion *)0)
,topology((Topology *)0)
,sa((SelfAwareness *)0)
,dp((DeferredPackets *)0)
@ -91,7 +89,6 @@ public:
Switch *sw;
Multicaster *mc;
AntiRecursion *antiRec;
Topology *topology;
SelfAwareness *sa;
DeferredPackets *dp;

View File

@ -42,7 +42,6 @@
#include "InetAddress.hpp"
#include "Topology.hpp"
#include "Peer.hpp"
#include "AntiRecursion.hpp"
#include "SelfAwareness.hpp"
#include "Packet.hpp"
#include "Cluster.hpp"
@ -97,7 +96,6 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from
_lastBeaconResponse = now;
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP);
outp.armor(peer->key(),true);
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(localAddr,fromAddr,outp.data(),outp.size());
}
}
@ -125,15 +123,6 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
if (to == network->mac())
return;
/* Check anti-recursion module to ensure that this is not ZeroTier talking over its own links.
* Note: even when we introduce a more purposeful binding of the main UDP port, this can
* still happen because Windows likes to send broadcasts over interfaces that have little
* to do with their intended target audience. :P */
if (!RR->antiRec->checkEthernetFrame(data,len)) {
TRACE("%.16llx: rejected recursively addressed ZeroTier packet by tail match (type %s, length: %u)",network->id(),etherTypeName(etherType),len);
return;
}
// Check to make sure this protocol is allowed on this network
if (!nconf->permitsEtherType(etherType)) {
TRACE("%.16llx: ignored tap: %s -> %s: ethertype %s not allowed on network %.16llx",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),(unsigned long long)network->id());