Ver código fonte

Match on tag sender equals or tag recipient equals.

Adam Ierymenko 8 anos atrás
pai
commit
2b10a982e9

+ 24 - 12
controller/EmbeddedNetworkController.cpp

@@ -218,6 +218,16 @@ static json _renderRule(ZT_VirtualNetworkRule &rule)
 				r["id"] = rule.v.tag.id;
 				r["value"] = rule.v.tag.value;
 				break;
+			case ZT_NETWORK_RULE_MATCH_TAG_SENDER:
+				r["type"] = "MATCH_TAG_SENDER";
+				r["id"] = rule.v.tag.id;
+				r["value"] = rule.v.tag.value;
+				break;
+			case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER:
+				r["type"] = "MATCH_TAG_RECEIVER";
+				r["id"] = rule.v.tag.id;
+				r["value"] = rule.v.tag.value;
+				break;
 			default:
 				break;
 		}
@@ -245,6 +255,7 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule)
 	if (OSUtils::jsonBool(r["or"],false))
 		rule.t |= 0x40;
 
+	bool tag = false;
 	if (t == "ACTION_DROP") {
 		rule.t |= ZT_NETWORK_RULE_ACTION_DROP;
 		return true;
@@ -388,26 +399,27 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule)
 		return true;
 	} else if (t == "MATCH_TAGS_DIFFERENCE") {
 		rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE;
-		rule.v.tag.id = (uint32_t)(OSUtils::jsonInt(r["id"],0ULL) & 0xffffffffULL);
-		rule.v.tag.value = (uint32_t)(OSUtils::jsonInt(r["value"],0ULL) & 0xffffffffULL);
-		return true;
+		tag = true;
 	} else if (t == "MATCH_TAGS_BITWISE_AND") {
 		rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND;
-		rule.v.tag.id = (uint32_t)(OSUtils::jsonInt(r["id"],0ULL) & 0xffffffffULL);
-		rule.v.tag.value = (uint32_t)(OSUtils::jsonInt(r["value"],0ULL) & 0xffffffffULL);
-		return true;
+		tag = true;
 	} else if (t == "MATCH_TAGS_BITWISE_OR") {
 		rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR;
-		rule.v.tag.id = (uint32_t)(OSUtils::jsonInt(r["id"],0ULL) & 0xffffffffULL);
-		rule.v.tag.value = (uint32_t)(OSUtils::jsonInt(r["value"],0ULL) & 0xffffffffULL);
-		return true;
+		tag = true;
 	} else if (t == "MATCH_TAGS_BITWISE_XOR") {
 		rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR;
-		rule.v.tag.id = (uint32_t)(OSUtils::jsonInt(r["id"],0ULL) & 0xffffffffULL);
-		rule.v.tag.value = (uint32_t)(OSUtils::jsonInt(r["value"],0ULL) & 0xffffffffULL);
-		return true;
+		tag = true;
 	} else if (t == "MATCH_TAGS_EQUAL") {
 		rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_EQUAL;
+		tag = true;
+	} else if (t == "MATCH_TAG_SENDER") {
+		rule.t |= ZT_NETWORK_RULE_MATCH_TAG_SENDER;
+		tag = true;
+	} else if (t == "MATCH_TAG_RECEIVER") {
+		rule.t |= ZT_NETWORK_RULE_MATCH_TAG_RECEIVER;
+		tag = true;
+	}
+	if (tag) {
 		rule.v.tag.id = (uint32_t)(OSUtils::jsonInt(r["id"],0ULL) & 0xffffffffULL);
 		rule.v.tag.value = (uint32_t)(OSUtils::jsonInt(r["value"],0ULL) & 0xffffffffULL);
 		return true;

+ 2 - 0
include/ZeroTierOne.h

@@ -604,6 +604,8 @@ enum ZT_VirtualNetworkRuleType
 	ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 46,
 	ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 47,
 	ZT_NETWORK_RULE_MATCH_TAGS_EQUAL = 48,
+	ZT_NETWORK_RULE_MATCH_TAG_SENDER = 49,
+	ZT_NETWORK_RULE_MATCH_TAG_RECEIVER = 50,
 
 	/**
 	 * Maximum ID allowed for a MATCH entry in the rules table

+ 5 - 3
node/Capability.hpp

@@ -167,9 +167,6 @@ public:
 			// rules to be ignored but still parsed.
 			b.append((uint8_t)rules[i].t);
 			switch((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3f)) {
-				//case ZT_NETWORK_RULE_ACTION_DROP:
-				//case ZT_NETWORK_RULE_ACTION_ACCEPT:
-				//case ZT_NETWORK_RULE_ACTION_DEBUG_LOG:
 				default:
 					b.append((uint8_t)0);
 					break;
@@ -258,6 +255,9 @@ public:
 				case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND:
 				case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR:
 				case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR:
+				case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL:
+				case ZT_NETWORK_RULE_MATCH_TAG_SENDER:
+				case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER:
 					b.append((uint8_t)8);
 					b.append((uint32_t)rules[i].v.tag.id);
 					b.append((uint32_t)rules[i].v.tag.value);
@@ -345,6 +345,8 @@ public:
 				case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR:
 				case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR:
 				case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL:
+				case ZT_NETWORK_RULE_MATCH_TAG_SENDER:
+				case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER:
 					rules[ruleCount].v.tag.id = b.template at<uint32_t>(p);
 					rules[ruleCount].v.tag.value = b.template at<uint32_t>(p + 4);
 					break;

+ 37 - 1
node/Network.cpp

@@ -515,7 +515,6 @@ static _doZtFilterResult _doZtFilter(
 						src.set((const void *)(frameData + 12),4,0);
 					} else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) {
 						// IPv6 NDP requires special handling, since the src and dest IPs in the packet are empty or link-local.
-						unsigned int pos = 0,proto = 0;
 						if ( (frameLen >= (40 + 8 + 16)) && (frameData[6] == 0x3a) && ((frameData[40] == 0x87)||(frameData[40] == 0x88)) ) {
 							if (frameData[40] == 0x87) {
 								// Neighbor solicitations contain no reliable source address, so we implement a small
@@ -609,6 +608,11 @@ static _doZtFilterResult _doZtFilter(
 							thisRuleMatches = 0;
 							FILTER_TRACE("%u %s %c remote tag %u not found -> 0 (inbound side is strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
 						} else {
+							// Outbound side is not strict since if we have to match both tags and
+							// we are sending a first packet to a recipient, we probably do not know
+							// about their tags yet. They will filter on inbound and we will filter
+							// once we get their tag. If we are a tee/redirect target we are also
+							// not strict since we likely do not have these tags.
 							thisRuleMatches = 1;
 							FILTER_TRACE("%u %s %c remote tag %u not found -> 1 (outbound side and TEE/REDIRECT targets are not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
 						}
@@ -618,6 +622,38 @@ static _doZtFilterResult _doZtFilter(
 					FILTER_TRACE("%u %s %c local tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
 				}
 			}	break;
+			case ZT_NETWORK_RULE_MATCH_TAG_SENDER:
+			case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: {
+				if (superAccept) {
+					thisRuleMatches = 1;
+					FILTER_TRACE("%u %s %c we are a TEE/REDIRECT target -> 1",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='));
+				} else if ( ((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER)&&(inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER)&&(!inbound)) ) {
+					const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0);
+					if (remoteTag) {
+						thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value);
+						FILTER_TRACE("%u %s %c TAG %u %.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,remoteTag->value(),(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches);
+					} else {
+						if (rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) {
+							// If we are checking the receiver and this is an outbound packet, we
+							// can't be strict since we may not yet know the receiver's tag.
+							thisRuleMatches = 1;
+							FILTER_TRACE("%u %s %c (inbound) remote tag %u not found -> 1 (outbound receiver match is not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
+						} else {
+							thisRuleMatches = 0;
+							FILTER_TRACE("%u %s %c (inbound) remote tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
+						}
+					}
+				} else { // sender and outbound or receiver and inbound
+					const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate());
+					if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) {
+						thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value);
+						FILTER_TRACE("%u %s %c TAG %u %.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,remoteTag->value(),(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches);
+					} else {
+						thisRuleMatches = 0;
+						FILTER_TRACE("%u %s %c local tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id);
+					}
+				}
+			}	break;
 
 			// The result of an unsupported MATCH is configurable at the network
 			// level via a flag.

+ 1 - 1
rule-compiler/package.json

@@ -1,6 +1,6 @@
 {
   "name": "zerotier-rule-compiler",
-  "version": "1.1.17-2",
+  "version": "1.1.17-3",
   "description": "ZeroTier Rule Script Compiler",
   "main": "cli.js",
   "scripts": {

+ 11 - 3
rule-compiler/rule-compiler.js

@@ -105,6 +105,8 @@ const RESERVED_WORDS = {
 	'txor': true,
 	'tdiff': true,
 	'teq': true,
+	'tseq': true,
+	'treq': true,
 
 	'type': true,
 	'enum': true,
@@ -152,7 +154,9 @@ const KEYWORD_TO_API_MAP = {
 	'tor': 'MATCH_TAGS_BITWISE_OR',
 	'txor': 'MATCH_TAGS_BITWISE_XOR',
 	'tdiff': 'MATCH_TAGS_DIFFERENCE',
-	'teq': 'MATCH_TAGS_EQUAL'
+	'teq': 'MATCH_TAGS_EQUAL',
+	'tseq': 'MATCH_TAG_SENDER',
+	'treq': 'MATCH_TAG_RECEIVER'
 };
 
 // Number of args for each match
@@ -179,7 +183,9 @@ const MATCH_ARG_COUNTS = {
 	'tor': 2,
 	'txor': 2,
 	'tdiff': 2,
-	'teq': 2
+	'teq': 2,
+	'tseq': 2,
+	'treq': 2
 };
 
 // Regex of all alphanumeric characters in Unicode
@@ -477,7 +483,9 @@ function _renderMatches(mtree,rules,macros,caps,tags,params)
 				case 'tor':
 				case 'txor':
 				case 'tdiff':
-				case 'teq': {
+				case 'teq':
+				case 'tseq':
+				case 'treq': {
 					let tag = tags[args[0][0]];
 					let tagId = -1;
 					let tagValue = -1;