From 4d9b74b171d243abe2d2d6a0039865ece8a4a00c Mon Sep 17 00:00:00 2001
From: Adam Ierymenko <adam.ierymenko@gmail.com>
Date: Thu, 4 Aug 2016 15:27:20 -0700
Subject: [PATCH] .

---
 include/ZeroTierOne.h   |  5 ++++
 node/Filter.cpp         |  7 ++---
 node/IncomingPacket.cpp | 60 +++--------------------------------------
 3 files changed, 13 insertions(+), 59 deletions(-)

diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h
index 88e83a6ef..2a70417ee 100644
--- a/include/ZeroTierOne.h
+++ b/include/ZeroTierOne.h
@@ -164,6 +164,11 @@ extern "C" {
  */
 #define ZT_CLUSTER_MAX_MESSAGE_LENGTH (1500 - 48)
 
+/**
+ * Packet characteristics flag: packet direction, 1 for incoming 0 for outgoing
+ */
+#define ZT_RULE_PACKET_CHARACTERISTICS_0_INBOUND 0x0000000000000001ULL
+
 /**
  * A null/empty sockaddr (all zero) to signify an unspecified socket address
  */
diff --git a/node/Filter.cpp b/node/Filter.cpp
index 286a0144b..b8b0bd2a1 100644
--- a/node/Filter.cpp
+++ b/node/Filter.cpp
@@ -239,9 +239,10 @@ bool Filter::run(
 					thisRuleMatches = 0;
 				}
 				break;
-			case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS:
-				// TODO: not supported yet
-				break;
+			case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: {
+				uint64_t cf = (receiving) ? ZT_RULE_PACKET_CHARACTERISTICS_0_INBOUND : 0ULL;
+				thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics[0]) == rules[rn].v.characteristics[1]);
+			}	break;
 			case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE:
 				thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1]));
 				break;
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index aea110d5b..c2df7ee2a 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -36,7 +36,6 @@
 #include "World.hpp"
 #include "Cluster.hpp"
 #include "Node.hpp"
-#include "Filter.hpp"
 #include "CertificateOfMembership.hpp"
 #include "Capability.hpp"
 #include "Tag.hpp"
@@ -541,23 +540,8 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 				const MAC sourceMac(peer->address(),network->id());
 				const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
 				const uint8_t *const frameData = reinterpret_cast<const uint8_t *>(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
-				if (Filter::run(
-					RR,
-					network->id(),
-					peer->address(),
-					RR->identity.address(),
-					sourceMac,
-					network->mac(),
-					frameData,
-					frameLen,
-					etherType,
-					0,
-					network->config().rules,
-					network->config().ruleCount))
-				{
+				if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0)) {
 					RR->node->putFrame(network->id(),network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen);
-				} else {
-					TRACE("dropped FRAME from %s(%s): Filter::run() == false (will still log packet as received)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id());
 				}
 			}
 
@@ -600,11 +584,6 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
 				const MAC to(field(comLen + 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(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM);
 
-				if (to.isMulticast()) {
-					TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: destination is multicast, must use MULTICAST_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str());
-					return true;
-				}
-
 				if ((!from)||(from.isMulticast())||(from == network->mac())) {
 					TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str());
 					return true;
@@ -626,23 +605,9 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
 
 				const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD);
 				const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen);
-				if (Filter::run(
-					RR,
-					network->id(),
-					peer->address(),
-					RR->identity.address(),
-					from,
-					to,
-					frameData,
-					frameLen,
-					etherType,
-					0,
-					network->config().rules,
-					network->config().ruleCount))
-				{
+
+				if (network->filterIncomingPacket(peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) {
 					RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen);
-				} else {
-					TRACE("dropped EXT_FRAME from %s(%s): Filter::run() == false (will still log packet as received)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id());
 				}
 			}
 
@@ -916,25 +881,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
 				}
 
 				const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen);
-				if (Filter::run(
-					RR,
-					network->id(),
-					peer->address(),
-					RR->identity.address(),
-					from,
-					to.mac(),
-					frameData,
-					frameLen,
-					etherType,
-					0,
-					network->config().rules,
-					network->config().ruleCount))
-				{
+				if (network->filterIncomingPacket(peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0)) {
 					RR->node->putFrame(network->id(),network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen);
-				} else {
-					TRACE("dropped MULTICAST_FRAME from %s(%s): Filter::run() == false (will still do implicit gather)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id());
-					// Note: we continue here since we still do implicit gather in this case... we just do not putFrame() if it
-					// fails the filter check.
 				}
 			}