diff --git a/node/Network.hpp b/node/Network.hpp index b40afd45f..0a89c8489 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -371,21 +371,6 @@ public: t->put(from,to,etherType,data,len); } - /** - * Inject a frame into tap with local MAC as destination MAC (if it's created) - * - * @param from Origin MAC - * @param etherType Ethernet frame type - * @param data Frame data - * @param len Frame length - */ - inline void tapPut(const MAC &from,unsigned int etherType,const void *data,unsigned int len) - { - EthernetTap *t = _tap; - if (t) - t->put(from,t->mac(),etherType,data,len); - } - /** * @return Tap device name or empty string if still initializing */ @@ -401,6 +386,7 @@ public: * @return Ethernet MAC address for this network's local interface */ inline const MAC &mac() const + throw() { return _mac; } @@ -416,6 +402,20 @@ public: return std::set(); } + /** + * Shortcut for config()->permitsBridging(), returns false if no config + * + * @param peer Peer address to check + * @return True if peer can bridge other Ethernet nodes into this network or network is in permissive bridging mode + */ + inline bool permitsBridging(const Address &peer) const + { + Mutex::Lock _l(_lock); + if (_config) + return _config->permitsBridging(peer); + return false; + } + /** * @param mac MAC address * @return ZeroTier address of bridge to this MAC or null address if not found diff --git a/node/Packet.hpp b/node/Packet.hpp index e2de9f574..833e95f18 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -176,6 +176,16 @@ #define ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + 8) #define ZT_PROTO_VERB_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2) +#define ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) +#define ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID 8 +#define ZT_PROTO_VERB_EXT_FRAME_IDX_TO (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID) +#define ZT_PROTO_VERB_EXT_FRAME_LEN_TO 6 +#define ZT_PROTO_VERB_EXT_FRAME_IDX_FROM (ZT_PROTO_VERB_EXT_FRAME_IDX_TO + ZT_PROTO_VERB_EXT_FRAME_LEN_TO) +#define ZT_PROTO_VERB_EXT_FRAME_LEN_FROM 6 +#define ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_EXT_FRAME_IDX_FROM + ZT_PROTO_VERB_EXT_FRAME_LEN_FROM) +#define ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE 2 +#define ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2) + #define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH (ZT_PACKET_IDX_PAYLOAD) #define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_DEPTH 2 #define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_FIFO (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_DEPTH) diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp index 6091196e1..c94caa3eb 100644 --- a/node/PacketDecoder.cpp +++ b/node/PacketDecoder.cpp @@ -405,47 +405,44 @@ bool PacketDecoder::_doRENDEZVOUS(const RuntimeEnvironment *_r,const SharedPtr

&peer,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) +{ + if (network->isAllowed(peer->address())) { + if (network->config()->permitsEtherType(etherType)) { + network->tapPut(from,to,etherType,data,len); + + /* Source moves "closer" to us in multicast propagation priority when + * we receive unicast frames from it. This is called "implicit social + * ordering" in other docs. */ + _r->mc->bringCloser(network->id(),peer->address()); + peer->receive(_r,_fromSock,_remoteAddress,hops(),packetId(),verb(),0,Packet::VERB_NOP,Utils::now()); + } else { + TRACE("dropped %s from %s@%s: ethernet type %u not allowed on network %.16llx",Packet::verbString(verb()),from.toString().c_str(),peer->address().toString().c_str(),etherType,(unsigned long long)network->id()); + } + } else { + TRACE("dropped %s from %s(%s): peer not a member of closed network %.16llx",Packet::verbString(verb()),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),network->id()); + + Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR); + outp.append((unsigned char)verb()); + outp.append(packetId()); + outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); + outp.append(network->id()); + outp.armor(peer->key(),true); + _fromSock->send(_remoteAddress,outp.data(),outp.size()); + } + return true; +} + bool PacketDecoder::_doFRAME(const RuntimeEnvironment *_r,const SharedPtr &peer) { try { SharedPtr network(_r->nc->network(at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID))); if (network) { - if (network->isAllowed(source())) { - unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); - if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { - if (network->config()->permitsEtherType(etherType)) { - network->tapPut( - MAC(source(),network->id()), - etherType, - data() + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD, - size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD); - } else { - TRACE("dropped FRAME from %s: ethernet type %u not allowed on network %.16llx",source().toString().c_str(),etherType,(unsigned long long)network->id()); - return true; - } - } else return true; // ignore empty frames - - // Source moves "closer" to us in multicast propagation priority when - // we receive unicast frames from it. This is called "implicit social - // ordering" in other docs. - _r->mc->bringCloser(network->id(),source()); - peer->receive(_r,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,Utils::now()); - } else { - TRACE("dropped FRAME from %s(%s): sender not a member of closed network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),network->id()); - - Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_FRAME); - outp.append(packetId()); - outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); - outp.append(network->id()); - outp.armor(peer->key(),true); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); - - return true; - } + unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); + if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) + _incomingFrame(_r,peer,network,MAC(peer->address(),network->id()),network->mac(),etherType,data() + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD); } else { TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); - return true; } } catch (std::exception &ex) { TRACE("dropped FRAME from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); @@ -457,6 +454,47 @@ bool PacketDecoder::_doFRAME(const RuntimeEnvironment *_r,const SharedPtr bool PacketDecoder::_doEXT_FRAME(const RuntimeEnvironment *_r,const SharedPtr &peer) { + try { + SharedPtr network(_r->nc->network(at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID))); + if (network) { + const MAC to(field(ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO); + const MAC from(field(ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM); + unsigned int etherType = at(ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); + if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { + if ((!from)||(from.isMulticast())||(!to)) { + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source or destination MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str()); + return true; + } + + if (from != MAC(peer->address(),network->id())) { + if (network->permitsBridging(peer->address())) { + network->learnBridgeRoute(from,peer->address()); + } else { + TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); + return true; + } + } + + if (to != network->mac()) { + /* For security reasons we should block incoming bridge packets if + * we are not a bridge. Bridging is a two way street, and unwanted + * bridging might open doors to strange things on untrusted nets. */ + if (!network->permitsBridging(_r->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(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); + return true; + } + } + + _incomingFrame(_r,peer,network,from,to,etherType,data() + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD); + } else return true; // ignore empty frames + } else { + TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + } + } catch (std::exception &ex) { + TRACE("dropped EXT_FRAME from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); + } catch ( ... ) { + TRACE("dropped EXT_FRAME from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str()); + } return true; } diff --git a/node/PacketDecoder.hpp b/node/PacketDecoder.hpp index 0a16ceb3f..3723fdda9 100644 --- a/node/PacketDecoder.hpp +++ b/node/PacketDecoder.hpp @@ -58,6 +58,7 @@ namespace ZeroTier { class RuntimeEnvironment; +class Network; /** * Subclass of packet that handles the decoding of it @@ -116,6 +117,7 @@ private: bool _doOK(const RuntimeEnvironment *_r,const SharedPtr &peer); bool _doWHOIS(const RuntimeEnvironment *_r,const SharedPtr &peer); bool _doRENDEZVOUS(const RuntimeEnvironment *_r,const SharedPtr &peer); + bool _incomingFrame(const RuntimeEnvironment *_r,const SharedPtr &peer,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); bool _doFRAME(const RuntimeEnvironment *_r,const SharedPtr &peer); bool _doEXT_FRAME(const RuntimeEnvironment *_r,const SharedPtr &peer); bool _doMULTICAST_FRAME(const RuntimeEnvironment *_r,const SharedPtr &peer); diff --git a/node/Peer.cpp b/node/Peer.cpp index c0cdaf170..54e30a74c 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -112,7 +112,7 @@ void Peer::receive( } } - if (verb == Packet::VERB_FRAME) + if ((verb == Packet::VERB_FRAME)||(verb == Packet::VERB_EXT_FRAME)) _lastUnicastFrame = now; else if (verb == Packet::VERB_MULTICAST_FRAME) _lastMulticastFrame = now;