Browse Source

Packet decoder work for EXT_FRAME for bridging - GitHub issue #68

Adam Ierymenko 11 years ago
parent
commit
c30f9832b0
5 changed files with 100 additions and 50 deletions
  1. 15 15
      node/Network.hpp
  2. 10 0
      node/Packet.hpp
  3. 72 34
      node/PacketDecoder.cpp
  4. 2 0
      node/PacketDecoder.hpp
  5. 1 1
      node/Peer.cpp

+ 15 - 15
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<InetAddress>();
 	}
 
+	/**
+	 * 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

+ 10 - 0
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)

+ 72 - 34
node/PacketDecoder.cpp

@@ -405,47 +405,44 @@ bool PacketDecoder::_doRENDEZVOUS(const RuntimeEnvironment *_r,const SharedPtr<P
 	return true;
 }
 
+bool PacketDecoder::_incomingFrame(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer,const SharedPtr<Network> &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> &peer)
 {
 	try {
 		SharedPtr<Network> network(_r->nc->network(at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)));
 		if (network) {
-			if (network->isAllowed(source())) {
-				unsigned int etherType = at<uint16_t>(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<uint16_t>(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<uint64_t>(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<Peer>
 
 bool PacketDecoder::_doEXT_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
 {
+	try {
+		SharedPtr<Network> network(_r->nc->network(at<uint64_t>(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<uint16_t>(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<uint64_t>(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;
 }
 

+ 2 - 0
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> &peer);
 	bool _doWHOIS(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
 	bool _doRENDEZVOUS(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
+	bool _incomingFrame(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer,const SharedPtr<Network> &network,const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
 	bool _doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
 	bool _doEXT_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
 	bool _doMULTICAST_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);

+ 1 - 1
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;