Match on tag sender equals or tag recipient equals.

This commit is contained in:
Adam Ierymenko 2017-02-28 09:22:10 -08:00
parent 31bece7fa0
commit 2b10a982e9
6 changed files with 80 additions and 20 deletions

View File

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

View File

@ -604,6 +604,8 @@ enum ZT_VirtualNetworkRuleType
ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 46, ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 46,
ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 47, ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 47,
ZT_NETWORK_RULE_MATCH_TAGS_EQUAL = 48, 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 * Maximum ID allowed for a MATCH entry in the rules table

View File

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

View File

@ -515,7 +515,6 @@ static _doZtFilterResult _doZtFilter(
src.set((const void *)(frameData + 12),4,0); src.set((const void *)(frameData + 12),4,0);
} else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { } 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. // 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 ( (frameLen >= (40 + 8 + 16)) && (frameData[6] == 0x3a) && ((frameData[40] == 0x87)||(frameData[40] == 0x88)) ) {
if (frameData[40] == 0x87) { if (frameData[40] == 0x87) {
// Neighbor solicitations contain no reliable source address, so we implement a small // Neighbor solicitations contain no reliable source address, so we implement a small
@ -609,6 +608,11 @@ static _doZtFilterResult _doZtFilter(
thisRuleMatches = 0; 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); 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 { } 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; 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); 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); 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; } 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 // The result of an unsupported MATCH is configurable at the network
// level via a flag. // level via a flag.

View File

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

View File

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