summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/ZeroTierOne.h219
-rw-r--r--node/Constants.hpp3
-rw-r--r--node/NetworkConfig.cpp25
-rw-r--r--node/NetworkConfig.hpp8
4 files changed, 192 insertions, 63 deletions
diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h
index b77cc820..75199195 100644
--- a/include/ZeroTierOne.h
+++ b/include/ZeroTierOne.h
@@ -107,9 +107,9 @@ extern "C" {
#define ZT_MAX_NETWORK_STATIC_DEVICES 32
/**
- * Maximum number of rules per network (can be increased)
+ * Maximum number of rule table entries per network (can be increased)
*/
-#define ZT_MAX_NETWORK_RULES 64
+#define ZT_MAX_NETWORK_RULES 256
/**
* Maximum number of multicast group subscriptions per network
@@ -432,102 +432,235 @@ enum ZT_VirtualNetworkType
*/
enum ZT_VirtualNetworkRuleAction
{
+ /**
+ * Drop frame
+ */
ZT_NETWORK_RULE_ACTION_DROP = 0,
- ZT_NETWORK_RULE_ACTION_ACCEPT = 1
+
+ /**
+ * Accept and pass frame
+ */
+ ZT_NETWORK_RULE_ACTION_ACCEPT = 1,
+
+ /**
+ * Forward a copy of this frame to an observer (in datum.zt[1])
+ */
+ ZT_NETWORK_RULE_ACTION_TEE = 2,
+
+ /**
+ * Redirect frame to ZeroTier device in datum.zt[1] regardless of Ethernet addressing or anything else
+ */
+ ZT_NETWORK_RULE_ACTION_REDIRECT = 3
};
/**
- * Network flow rule
- *
- * Currently only etherType is supported! Other flags will have no effect
- * until the rules engine is fully implemented.
+ * Datum type (variant) that a rule matches
*/
-typedef struct
+enum ZT_VirtualNetworkRuleMatches
{
/**
- * Rule sort order
+ * Matches all packets (no criteria)
+ */
+ ZT_NETWORK_RULE_MATCHES_ALL = 0,
+
+ /**
+ * Source ZeroTier address -- analogous to an Ethernet port ID on a switch
*/
- int ruleNo;
+ ZT_NETWORK_RULE_MATCHES_SOURCE_ZEROTIER_ADDRESS = 1,
/**
- * Source ZeroTier address ("port" on the global virtual switch) (0 == wildcard)
+ * Destination ZeroTier address -- analogous to an Ethernet port ID on a switch
*/
- uint64_t sourcePort;
+ ZT_NETWORK_RULE_MATCHES_DEST_ZEROTIER_ADDRESS = 2,
/**
- * Destination ZeroTier address ("port" on the global virtual switch) (0 == wildcard)
+ * Ethernet VLAN ID
*/
- uint64_t destPort;
+ ZT_NETWORK_RULE_MATCHES_VLAN_ID = 3,
+
+ /**
+ * Ethernet VLAN PCP
+ */
+ ZT_NETWORK_RULE_MATCHES_VLAN_PCP = 4,
/**
- * VLAN ID (-1 == wildcard)
+ * Ethernet VLAN DEI
*/
- int vlanId;
+ ZT_NETWORK_RULE_MATCHES_VLAN_DEI = 5,
/**
- * VLAN PCP (-1 == wildcard)
+ * Ethernet frame type
*/
- int vlanPcp;
+ ZT_NETWORK_RULE_MATCHES_ETHERTYPE = 6,
/**
- * Ethernet type (-1 == wildcard)
+ * Source Ethernet MAC address
*/
- int etherType;
+ ZT_NETWORK_RULE_MATCHES_MAC_SOURCE = 7,
/**
- * Source MAC address (least significant 48 bits, host byte order) (0 == wildcard)
+ * Destination Ethernet MAC address
*/
- uint64_t macSource;
+ ZT_NETWORK_RULE_MATCHES_MAC_DEST = 8,
- /**
- * Destination MAC address (least significant 48 bits, host byte order) (0 == wildcard)
+ /**
+ * Source IPv4 address
+ */
+ ZT_NETWORK_RULE_MATCHES_IPV4_SOURCE = 9,
+
+ /**
+ * Destination IPv4 address
*/
- uint64_t macDest;
+ ZT_NETWORK_RULE_MATCHES_IPV4_DEST = 10,
/**
- * Source IP address (ss_family == 0 for wildcard)
+ * Source IPv6 address
*/
- struct sockaddr_storage ipSource;
+ ZT_NETWORK_RULE_MATCHES_IPV6_SOURCE = 11,
/**
- * Destination IP address (ss_family == 0 for wildcard)
+ * Destination IPv6 address
*/
- struct sockaddr_storage ipDest;
+ ZT_NETWORK_RULE_MATCHES_IPV6_DEST = 12,
/**
- * IP type of service (-1 == wildcard)
+ * IP TOS (type of service)
*/
- int ipTos;
+ ZT_NETWORK_RULE_MATCHES_IP_TOS = 13,
/**
- * IP protocol (-1 == wildcard)
+ * IP protocol
*/
- int ipProtocol;
+ ZT_NETWORK_RULE_MATCHES_IP_PROTOCOL = 14,
/**
- * IP source port (-1 == wildcard)
+ * IP source port range (start-end, inclusive)
*/
- int ipSourcePort;
+ ZT_NETWORK_RULE_MATCHES_IP_SOURCE_PORT_RANGE = 15,
/**
- * IP destination port (-1 == wildcard)
+ * IP destination port range (start-end, inclusive)
*/
- int ipDestPort;
+ ZT_NETWORK_RULE_MATCHES_IP_DEST_PORT_RANGE = 16,
/**
- * Flags to match if set
+ * Packet characteristic flags
*/
- unsigned long flags;
+ ZT_NETWORK_RULE_MATCHES_FLAGS = 17,
/**
- * Flags to match if NOT set
+ * Frame size range (start-end, inclusive)
*/
- unsigned long invFlags;
+ ZT_NETWORK_RULE_MATCHES_FRAME_SIZE_RANGE = 18
+};
+
+/**
+ * Network flow rule
+ *
+ * NOTE: Currently (1.1.x) only etherType is supported! Other things will
+ * have no effect until the rules engine is fully implemented.
+ *
+ * Multiple entries in the table can have the same ruleNo. This indicates
+ * a row with multiple matching criteria.
+ *
+ * This gives the table a much more space-efficient compressed representation,
+ * allowing far more rules to be efficiently sent in small netconf structures.
+ */
+typedef struct
+{
+ /**
+ * Rule number and sort order
+ *
+ * Multiple entries in the table can have the same ruleNo. This causes them
+ * to be matched as an AND together, e.g. both IP source and IP source port.
+ */
+ uint16_t ruleNo;
+
+ /**
+ * Field that this rules table entry matches (enum ZT_VirtualNetworkRuleMatches)
+ */
+ uint8_t matches;
/**
- * Action if rule matches
+ * Action if rule matches (enum ZT_VirtualNetworkRuleAction)
*/
- enum ZT_VirtualNetworkRuleAction action;
+ uint8_t action;
+
+ /**
+ * Union containing the datum for this rule
+ *
+ * The rule entry functions like a variant type, with the field of datum
+ * that is relevant/valid determined by the 'matches' enum.
+ */
+ union {
+ /**
+ * IPv6 address in big-endian / network byte order
+ */
+ uint8_t ipv6[16];
+
+ /**
+ * Flags (128 possible)
+ */
+ uint8_t flags[16];
+
+ /**
+ * IPv4 address in big-endian / network byte order
+ */
+ uint32_t ipv4;
+
+ /**
+ * IP port range -- start-end inclusive -- host byte order
+ */
+ uint16_t port[2];
+
+ /**
+ * Two possible 40-bit ZeroTier addresses in host byte order (least significant 40 bits of uint64_t)
+ *
+ * The first of these ([0]) is used in most cases e.g. matching ZT source
+ * address. The second is used as the observer for the TEE action.
+ */
+ uint64_t zt[2];
+
+ /**
+ * 48-bit Ethernet MAC address in big-endian order
+ */
+ uint8_t mac[6];
+
+ /**
+ * VLAN ID in host byte order
+ */
+ uint16_t vlanId;
+
+ /**
+ * VLAN PCP (least significant 3 bits)
+ */
+ uint8_t vlanPcp;
+
+ /**
+ * VLAN DEI (single bit / boolean)
+ */
+ uint8_t vlanDei;
+
+ /**
+ * Ethernet type in host byte order
+ */
+ uint16_t etherType;
+
+ /**
+ * IP protocol
+ */
+ uint8_t ipProtocol;
+
+ /**
+ * IP type of service
+ */
+ uint8_t ipTos;
+
+ /**
+ * Ethernet packet size in host byte order (start-end, inclusive)
+ */
+ uint16_t frameSize[2];
+ } datum;
} ZT_VirtualNetworkRule;
/**
diff --git a/node/Constants.hpp b/node/Constants.hpp
index 4bca7d29..dc36b3a1 100644
--- a/node/Constants.hpp
+++ b/node/Constants.hpp
@@ -286,6 +286,9 @@
/**
* Delay between requests for updated network autoconf information
+ *
+ * Don't lengthen this as it affects things like QoS / uptime monitoring
+ * via ZeroTier Central. This is the heartbeat, basically.
*/
#define ZT_NETWORK_AUTOCONF_DELAY 60000
diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp
index aab9a650..090648f8 100644
--- a/node/NetworkConfig.cpp
+++ b/node/NetworkConfig.cpp
@@ -56,16 +56,10 @@ NetworkConfig NetworkConfig::createTestNetworkConfig(const Address &self)
nc._type = ZT_NETWORK_TYPE_PUBLIC;
nc._enableBroadcast = true;
- nc._rules[nc._ruleCount].ruleNo = 0;
- nc._rules[nc._ruleCount].vlanId = -1;
- nc._rules[nc._ruleCount].vlanPcp = -1;
- nc._rules[nc._ruleCount].etherType = -1;
- nc._rules[nc._ruleCount].ipTos = -1;
- nc._rules[nc._ruleCount].ipProtocol = -1;
- nc._rules[nc._ruleCount].ipSourcePort = -1;
- nc._rules[nc._ruleCount].ipDestPort = -1;
- nc._rules[nc._ruleCount].action = ZT_NETWORK_RULE_ACTION_ACCEPT;
- ++nc._ruleCount;
+ nc._rules[nc._ruleCount].ruleNo = 1;
+ nc._rules[nc._ruleCount].matches = (uint8_t)ZT_NETWORK_RULE_MATCHES_ALL;
+ nc._rules[nc._ruleCount].action = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
+ nc._ruleCount = 1;
Utils::snprintf(nc._name,sizeof(nc._name),"ZT_TEST_NETWORK");
@@ -213,14 +207,9 @@ void NetworkConfig::fromDictionary(const Dictionary &d)
if (_ruleCount < ZT_MAX_NETWORK_RULES) {
memset(&(_rules[_ruleCount]),0,sizeof(ZT_VirtualNetworkRule));
_rules[_ruleCount].ruleNo = rno; rno += 10;
- _rules[_ruleCount].vlanId = -1;
- _rules[_ruleCount].vlanPcp = -1;
- _rules[_ruleCount].etherType = (et2 == 0) ? -1 : (int)et2;
- _rules[_ruleCount].ipTos = -1;
- _rules[_ruleCount].ipProtocol = -1;
- _rules[_ruleCount].ipSourcePort = -1;
- _rules[_ruleCount].ipDestPort = -1;
- _rules[_ruleCount].action = ZT_NETWORK_RULE_ACTION_ACCEPT;
+ _rules[_ruleCount].matches = (uint8_t)((et2 == 0) ? ZT_NETWORK_RULE_MATCHES_ALL : ZT_NETWORK_RULE_MATCHES_ETHERTYPE);
+ _rules[_ruleCount].action = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
+ _rules[_ruleCount].datum.etherType = (uint16_t)et2;
++_ruleCount;
}
}
diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp
index c3cc9cd4..0ed7b6a2 100644
--- a/node/NetworkConfig.hpp
+++ b/node/NetworkConfig.hpp
@@ -133,8 +133,12 @@ public:
inline bool permitsEtherType(unsigned int etherType) const
{
for(unsigned int i=0;i<_ruleCount;++i) {
- if ((_rules[i].etherType < 0)||((unsigned int)_rules[i].etherType == etherType))
- return (_rules[i].action == ZT_NETWORK_RULE_ACTION_ACCEPT);
+ if ((ZT_VirtualNetworkRuleMatches)_rules[i].matches == ZT_NETWORK_RULE_MATCHES_ETHERTYPE) {
+ if (_rules[i].datum.etherType == etherType)
+ return ((ZT_VirtualNetworkRuleAction)_rules[i].action == ZT_NETWORK_RULE_ACTION_ACCEPT);
+ } else if ((ZT_VirtualNetworkRuleMatches)_rules[i].matches == ZT_NETWORK_RULE_MATCHES_ALL) {
+ return ((ZT_VirtualNetworkRuleAction)_rules[i].action == ZT_NETWORK_RULE_ACTION_ACCEPT);
+ }
}
return false;
}