diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2014-04-10 14:22:25 -0700 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2014-04-10 14:22:25 -0700 |
commit | c9294c1a78fa86fbba38b1a81988ea7527b0872c (patch) | |
tree | 0a2b3b88014b244020864839d4517a92ef1b5948 /node | |
parent | b117ff54358d4e2b6b8eae4bd5300464f377d948 (diff) | |
download | infinitytier-c9294c1a78fa86fbba38b1a81988ea7527b0872c.tar.gz infinitytier-c9294c1a78fa86fbba38b1a81988ea7527b0872c.zip |
Prevent recursive transit of ZeroTier packets, toward GitHub issue #56
Diffstat (limited to 'node')
-rw-r--r-- | node/AntiRecursion.hpp | 110 | ||||
-rw-r--r-- | node/Constants.hpp | 5 | ||||
-rw-r--r-- | node/Node.cpp | 16 | ||||
-rw-r--r-- | node/Peer.cpp | 2 | ||||
-rw-r--r-- | node/RuntimeEnvironment.hpp | 3 | ||||
-rw-r--r-- | node/Switch.cpp | 18 |
6 files changed, 141 insertions, 13 deletions
diff --git a/node/AntiRecursion.hpp b/node/AntiRecursion.hpp new file mode 100644 index 00000000..82cf9e58 --- /dev/null +++ b/node/AntiRecursion.hpp @@ -0,0 +1,110 @@ +/* + * ZeroTier One - Global Peer to Peer Ethernet + * Copyright (C) 2011-2014 ZeroTier Networks LLC + * + * 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 { + +#define ZT_ANTIRECURSION_TAIL_LEN 256 + +/** + * 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 N + * 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. + * + * NOTE: this is applied to low-level packets before they are sent to + * SocketManager and/or sockets, not to fully assembled packets before + * (possible) fragmentation. + */ +class AntiRecursion +{ +public: + AntiRecursion() + throw() + { + memset(_history,0,sizeof(_history)); + _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 *data,unsigned int len) + throw() + { + ArItem *i = &(_history[_ptr++ % ZT_ANTIRECURSION_HISTORY_SIZE]); + const unsigned int tl = (len > ZT_ANTIRECURSION_TAIL_LEN) ? ZT_ANTIRECURSION_TAIL_LEN : len; + memcpy(i->tail,((const unsigned char *)data) + (len - tl),tl); + i->len = tl; + } + + /** + * 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 *data,unsigned int len) + throw() + { + for(unsigned int h=0;h<ZT_ANTIRECURSION_HISTORY_SIZE;++h) { + ArItem *i = &(_history[h]); + if ((len >= i->len)&&(!memcmp(((const unsigned char *)data) + (len - i->len),i->tail,i->len))) + return false; + } + return true; + } + +private: + struct ArItem + { + unsigned char tail[ZT_ANTIRECURSION_TAIL_LEN]; + unsigned int len; + }; + ArItem _history[ZT_ANTIRECURSION_HISTORY_SIZE]; + volatile unsigned int _ptr; +}; + +} // namespace ZeroTier + +#endif diff --git a/node/Constants.hpp b/node/Constants.hpp index 2b958088..589f8641 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -362,6 +362,11 @@ error_no_byte_order_defined; #define ZT_RENDEZVOUS_NAT_T_DELAY 500 /** + * Size of anti-recursion history (see AntiRecursion.hpp) + */ +#define ZT_ANTIRECURSION_HISTORY_SIZE 16 + +/** * Minimum interval between attempts to do a software update */ #define ZT_UPDATE_MIN_INTERVAL 120000 diff --git a/node/Node.cpp b/node/Node.cpp index 26c1d90b..655e3188 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -52,6 +52,8 @@ #include <sys/file.h> #endif +#include "../version.h" + #include "Node.hpp" #include "RuntimeEnvironment.hpp" #include "Logger.hpp" @@ -73,8 +75,7 @@ #include "SoftwareUpdater.hpp" #include "Buffer.hpp" #include "IpcConnection.hpp" - -#include "../version.h" +#include "AntiRecursion.hpp" namespace ZeroTier { @@ -235,24 +236,16 @@ struct _NodeImpl #ifndef __WINDOWS__ delete renv.netconfService; - TRACE("shutdown: delete netconfService"); #endif delete renv.updater; - TRACE("shutdown: delete updater"); delete renv.nc; - TRACE("shutdown: delete nc"); delete renv.sysEnv; - TRACE("shutdown: delete sysEnv"); delete renv.topology; - TRACE("shutdown: delete topology"); delete renv.sm; - TRACE("shutdown: delete sm"); delete renv.sw; - TRACE("shutdown: delete sw"); delete renv.mc; - TRACE("shutdown: delete mc"); + delete renv.antiRec; delete renv.prng; - TRACE("shutdown: delete prng"); delete renv.log; return reasonForTermination; @@ -477,6 +470,7 @@ Node::ReasonForTermination Node::run() Utils::lockDownFile(configAuthTokenPath.c_str(),false); // Create the objects that make up runtime state. + _r->antiRec = new AntiRecursion(); _r->mc = new Multicaster(); _r->sw = new Switch(_r); _r->sm = new SocketManager(impl->udpPort,impl->tcpPort,&_CBztTraffic,_r); diff --git a/node/Peer.cpp b/node/Peer.cpp index 5c87275f..3aeb821e 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -27,6 +27,7 @@ #include "Peer.hpp" #include "Switch.hpp" +#include "AntiRecursion.hpp" #include <algorithm> @@ -164,6 +165,7 @@ Path::Type Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int if ((bestPath)&&(_r->sm->send(bestPath->address(),bestPath->tcp(),bestPath->type() == Path::PATH_TYPE_TCP_OUT,data,len))) { bestPath->sent(now); + _r->antiRec->logOutgoingZT(data,len); return bestPath->type(); } return Path::PATH_TYPE_NULL; diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index e8518b97..8887b081 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -46,6 +46,7 @@ class Node; class Multicaster; class SoftwareUpdater; class SocketManager; +class AntiRecursion; /** * Holds global state for an instance of ZeroTier::Node @@ -69,6 +70,7 @@ public: timeOfLastPacketReceived(0), log((Logger *)0), prng((CMWC4096 *)0), + antiRec((AntiRecursion *)0), mc((Multicaster *)0), sw((Switch *)0), sm((SocketManager *)0), @@ -111,6 +113,7 @@ public: Logger *log; // null if logging is disabled CMWC4096 *prng; + AntiRecursion *antiRec; Multicaster *mc; Switch *sw; SocketManager *sm; diff --git a/node/Switch.cpp b/node/Switch.cpp index 1c794176..2bdc1bef 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -48,6 +48,7 @@ #include "Peer.hpp" #include "NodeConfig.hpp" #include "CMWC4096.hpp" +#include "AntiRecursion.hpp" #include "../version.h" @@ -85,6 +86,11 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c if (!nconf) return; + if (!_r->antiRec->checkEthernetFrame(data.data(),data.size())) { + TRACE("%s: rejected recursively addressed ZeroTier packet by tail match",network->tapDeviceName().c_str()); + return; + } + if (to == network->mac()) { LOG("%s: frame received from self, ignoring (bridge loop? OS bug?)",network->tapDeviceName().c_str()); return; @@ -225,7 +231,11 @@ bool Switch::sendHELLO(const SharedPtr<Peer> &dest,const Path &path) outp.append(now); _r->identity.serialize(outp,false); outp.armor(dest->key(),false); - return _r->sm->send(path.address(),path.tcp(),path.type() == Path::PATH_TYPE_TCP_OUT,outp.data(),outp.size()); + if (_r->sm->send(path.address(),path.tcp(),path.type() == Path::PATH_TYPE_TCP_OUT,outp.data(),outp.size())) { + _r->antiRec->logOutgoingZT(outp.data(),outp.size()); + return true; + } + return false; } bool Switch::sendHELLO(const SharedPtr<Peer> &dest,const InetAddress &destUdp) @@ -239,7 +249,11 @@ bool Switch::sendHELLO(const SharedPtr<Peer> &dest,const InetAddress &destUdp) outp.append(now); _r->identity.serialize(outp,false); outp.armor(dest->key(),false); - return _r->sm->send(destUdp,false,false,outp.data(),outp.size()); + if (_r->sm->send(destUdp,false,false,outp.data(),outp.size())) { + _r->antiRec->logOutgoingZT(outp.data(),outp.size()); + return true; + } + return false; } bool Switch::unite(const Address &p1,const Address &p2,bool force) |