فهرست منبع

Merge branch 'dev' into fix-mac-handling-in-rules-parser

Joseph Henry 1 سال پیش
والد
کامیت
43b141547e

+ 7 - 1
README.md

@@ -44,6 +44,12 @@ The base path contains the ZeroTier One service main entry point (`one.cpp`), se
  - `windows/`: Visual Studio solution files, Windows service code, and the Windows task bar app UI.
  - `windows/`: Visual Studio solution files, Windows service code, and the Windows task bar app UI.
  - `zeroidc/`: OIDC implementation used by ZeroTier service to log into SSO-enabled networks. (This part is written in Rust, and more Rust will be appearing in this repository in the future.)
  - `zeroidc/`: OIDC implementation used by ZeroTier service to log into SSO-enabled networks. (This part is written in Rust, and more Rust will be appearing in this repository in the future.)
 
 
+### Contributing
+
+Please do pull requests off of the `dev` branch.
+
+Releases are done by merging `dev` into `main` and then tagging and doing builds. 
+
 ### Build and Platform Notes
 ### Build and Platform Notes
 
 
 To build on Mac and Linux just type `make`. On FreeBSD and OpenBSD `gmake` (GNU make) is required and can be installed from packages or ports. For Windows there is a Visual Studio solution in `windows/`.
 To build on Mac and Linux just type `make`. On FreeBSD and OpenBSD `gmake` (GNU make) is required and can be installed from packages or ports. For Windows there is a Visual Studio solution in `windows/`.
@@ -81,7 +87,7 @@ On most distributions, macOS, and Windows, the installer will start the service
 
 
 A home folder for your system will automatically be created.
 A home folder for your system will automatically be created.
 
 
-The service is controlled via the JSON API, which by default is available at 127.0.0.1 port 9993. We include a *zerotier-cli* command line utility to make API calls for standard things like joining and leaving networks. The *authtoken.secret* file in the home folder contains the secret token for accessing this API. See [service/README.md](service/README.md) for API documentation.
+The service is controlled via the JSON API, which by default is available at `127.0.0.1:9993`. It also listens on `0.0.0.0:9993` which is only usable if `allowManagementFrom` is properly configured in `local.conf`. We include a *zerotier-cli* command line utility to make API calls for standard things like joining and leaving networks. The *authtoken.secret* file in the home folder contains the secret token for accessing this API. See [service/README.md](service/README.md) for API documentation.
 
 
 Here's where home folders live (by default) on each OS:
 Here's where home folders live (by default) on each OS:
 
 

+ 1 - 1
controller/DB.cpp

@@ -196,7 +196,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohma
 void DB::networks(std::set<uint64_t> &networks)
 void DB::networks(std::set<uint64_t> &networks)
 {
 {
 	waitForReady();
 	waitForReady();
-	Metrics::db_get_member_list++;
+	Metrics::db_get_network_list++;
 	std::shared_lock<std::shared_mutex> l(_networks_l);
 	std::shared_lock<std::shared_mutex> l(_networks_l);
 	for(auto n=_networks.begin();n!=_networks.end();++n)
 	for(auto n=_networks.begin();n!=_networks.end();++n)
 		networks.insert(n->first);
 		networks.insert(n->first);

+ 91 - 1
controller/EmbeddedNetworkController.cpp

@@ -869,9 +869,11 @@ void EmbeddedNetworkController::configureHTTPControlPlane(
 	// Control plane Endpoints
 	// Control plane Endpoints
 	std::string controllerPath = "/controller";
 	std::string controllerPath = "/controller";
 	std::string networkListPath = "/controller/network";
 	std::string networkListPath = "/controller/network";
+	std::string networkListPath2 = "/unstable/controller/network";
 	std::string networkPath = "/controller/network/([0-9a-fA-F]{16})";
 	std::string networkPath = "/controller/network/([0-9a-fA-F]{16})";
 	std::string oldAndBustedNetworkCreatePath = "/controller/network/([0-9a-fA-F]{10})______";
 	std::string oldAndBustedNetworkCreatePath = "/controller/network/([0-9a-fA-F]{10})______";
 	std::string memberListPath = "/controller/network/([0-9a-fA-F]{16})/member";
 	std::string memberListPath = "/controller/network/([0-9a-fA-F]{16})/member";
+	std::string memberListPath2 = "/unstable/controller/network/([0-9a-fA-F]{16})/member";
 	std::string memberPath = "/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})";
 	std::string memberPath = "/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})";
 
 
 	auto controllerGet = [&, setContent](const httplib::Request &req, httplib::Response &res) {
 	auto controllerGet = [&, setContent](const httplib::Request &req, httplib::Response &res) {
@@ -910,6 +912,52 @@ void EmbeddedNetworkController::configureHTTPControlPlane(
 	s.Get(networkListPath, networkListGet);
 	s.Get(networkListPath, networkListGet);
 	sv6.Get(networkListPath, networkListGet);
 	sv6.Get(networkListPath, networkListGet);
 
 
+	auto networkListGet2 = [&, setContent](const httplib::Request &req, httplib::Response &res) {
+		std::set<uint64_t> networkIds;
+		_db.networks(networkIds);
+
+		auto meta = json::object();
+		auto data = json::array();
+		uint64_t networkCount = 0;
+
+		for(std::set<uint64_t>::const_iterator nwid(networkIds.begin()); nwid != networkIds.end(); ++nwid) {
+			json network;
+			if (!_db.get(*nwid, network)) {
+				continue;
+			}
+
+			std::vector<json> memTmp;
+			if (_db.get(*nwid, network, memTmp)) {
+				if (!network.is_null()) {
+					uint64_t authorizedCount = 0;
+					uint64_t totalCount = memTmp.size();
+					networkCount++;
+
+					for (auto m = memTmp.begin(); m != memTmp.end(); ++m) {
+						bool a = OSUtils::jsonBool((*m)["authorized"], 0);
+						if (a) { authorizedCount++; }
+					}
+
+					auto nwMeta = json::object();
+					nwMeta["totalMemberCount"] = totalCount;
+					nwMeta["authorizedMemberCount"] = authorizedCount;
+					network["meta"] = nwMeta;
+
+					data.push_back(network);
+				}
+			}
+		}
+		meta["networkCount"] = networkCount;
+
+		auto out = json::object();
+		out["data"] = data;
+		out["meta"] = meta;
+
+		setContent(req, res, out.dump());
+	};
+	s.Get(networkListPath2, networkListGet2);
+	sv6.Get(networkListPath2, networkListGet2);
+
 	auto networkGet = [&, setContent](const httplib::Request &req, httplib::Response &res) {
 	auto networkGet = [&, setContent](const httplib::Request &req, httplib::Response &res) {
 		auto networkID = req.matches[1];
 		auto networkID = req.matches[1];
 		uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str());
 		uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str());
@@ -925,7 +973,7 @@ void EmbeddedNetworkController::configureHTTPControlPlane(
 	sv6.Get(networkPath, networkGet);
 	sv6.Get(networkPath, networkGet);
 
 
 	auto createNewNetwork = [&, setContent](const httplib::Request &req, httplib::Response &res) {
 	auto createNewNetwork = [&, setContent](const httplib::Request &req, httplib::Response &res) {
-		fprintf(stderr, "creating new network (new style)\n");
+		// fprintf(stderr, "creating new network (new style)\n");
 		uint64_t nwid = 0;
 		uint64_t nwid = 0;
 		uint64_t nwidPrefix = (Utils::hexStrToU64(_signingIdAddressString.c_str()) << 24) & 0xffffffffff000000ULL;
 		uint64_t nwidPrefix = (Utils::hexStrToU64(_signingIdAddressString.c_str()) << 24) & 0xffffffffff000000ULL;
 		uint64_t nwidPostfix = 0;
 		uint64_t nwidPostfix = 0;
@@ -1035,6 +1083,41 @@ void EmbeddedNetworkController::configureHTTPControlPlane(
 	s.Get(memberListPath, memberListGet);
 	s.Get(memberListPath, memberListGet);
 	sv6.Get(memberListPath, memberListGet);
 	sv6.Get(memberListPath, memberListGet);
 
 
+	auto memberListGet2 = [&, setContent](const httplib::Request &req, httplib::Response &res) {
+		auto networkID = req.matches[1];
+		uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str());
+		json network;
+		if (!_db.get(nwid, network)) {
+			res.status = 404;
+			return;
+		}
+
+		auto out = nlohmann::json::object();
+		auto meta = nlohmann::json::object();
+		std::vector<json> memTmp;
+		if (_db.get(nwid, network, memTmp)) {
+			uint64_t authorizedCount = 0;
+			uint64_t totalCount = memTmp.size();
+			for (auto m = memTmp.begin(); m != memTmp.end(); ++m) {
+				bool a = OSUtils::jsonBool((*m)["authorized"], 0);
+				if (a) { authorizedCount++; }
+			}
+
+			meta["totalCount"] = totalCount;
+			meta["authorizedCount"] = authorizedCount;
+
+			out["data"] = memTmp;
+			out["meta"] = meta;
+
+			setContent(req, res, out.dump());
+		} else {
+			res.status = 404;
+			return;
+		}
+	};
+	s.Get(memberListPath2, memberListGet2);
+	sv6.Get(memberListPath2, memberListGet2);
+
 	auto memberGet = [&, setContent](const httplib::Request &req, httplib::Response &res) {
 	auto memberGet = [&, setContent](const httplib::Request &req, httplib::Response &res) {
 		auto networkID = req.matches[1];
 		auto networkID = req.matches[1];
 		auto memberID = req.matches[2];
 		auto memberID = req.matches[2];
@@ -1057,6 +1140,12 @@ void EmbeddedNetworkController::configureHTTPControlPlane(
 		auto memberID = req.matches[2].str();
 		auto memberID = req.matches[2].str();
 		uint64_t nwid = Utils::hexStrToU64(networkID.c_str());
 		uint64_t nwid = Utils::hexStrToU64(networkID.c_str());
 		uint64_t memid = Utils::hexStrToU64(memberID.c_str());
 		uint64_t memid = Utils::hexStrToU64(memberID.c_str());
+
+		if (!_db.hasNetwork(nwid)) {
+			res.status = 404;
+			return;
+		}
+
 		json network;
 		json network;
 		json member;
 		json member;
 		_db.get(nwid, network, memid, member);
 		_db.get(nwid, network, memid, member);
@@ -1068,6 +1157,7 @@ void EmbeddedNetworkController::configureHTTPControlPlane(
 		if (b.count("noAutoAssignIps")) member["noAutoAssignIps"] = OSUtils::jsonBool(b["noAutoAssignIps"], false);
 		if (b.count("noAutoAssignIps")) member["noAutoAssignIps"] = OSUtils::jsonBool(b["noAutoAssignIps"], false);
 		if (b.count("authenticationExpiryTime")) member["authenticationExpiryTime"] = (uint64_t)OSUtils::jsonInt(b["authenticationExpiryTime"], 0ULL);
 		if (b.count("authenticationExpiryTime")) member["authenticationExpiryTime"] = (uint64_t)OSUtils::jsonInt(b["authenticationExpiryTime"], 0ULL);
 		if (b.count("authenticationURL")) member["authenticationURL"] = OSUtils::jsonString(b["authenticationURL"], "");
 		if (b.count("authenticationURL")) member["authenticationURL"] = OSUtils::jsonString(b["authenticationURL"], "");
+		if (b.count("name")) member["name"] = OSUtils::jsonString(b["name"], "");
 
 
 		if (b.count("remoteTraceTarget")) {
 		if (b.count("remoteTraceTarget")) {
 			const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],""));
 			const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],""));

+ 1 - 1
controller/FileDB.cpp

@@ -136,7 +136,7 @@ void FileDB::eraseNetwork(const uint64_t networkId)
 	char p[16384];
 	char p[16384];
 	OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),networkId);
 	OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),networkId);
 	OSUtils::rm(p);
 	OSUtils::rm(p);
-	OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member",_networksPath.c_str(),(unsigned long long)networkId);
+	OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx",_networksPath.c_str(),(unsigned long long)networkId);
 	OSUtils::rmDashRf(p);
 	OSUtils::rmDashRf(p);
 	_networkChanged(network,nullJson,true);
 	_networkChanged(network,nullJson,true);
 	std::lock_guard<std::mutex> l(this->_online_l);
 	std::lock_guard<std::mutex> l(this->_online_l);

+ 15 - 1
controller/PostgreSQL.cpp

@@ -1436,7 +1436,21 @@ void PostgreSQL::commitThread()
 					w.commit();
 					w.commit();
 
 
 					if (_smee != NULL && isNewMember) {
 					if (_smee != NULL && isNewMember) {
-						notifyNewMember(networkId, memberId);
+						pqxx::row row = w.exec_params1(
+							"SELECT "
+							"	count(h.hook_id) "
+							"FROM "
+							"	ztc_hook h "
+							"	INNER JOIN ztc_org o ON o.org_id = h.org_id "
+							"   INNER JOIN ztc_network n ON n.owner_id = o.owner_id "
+							" WHERE "
+							"n.id = $1 ",
+							networkId
+						);
+						int64_t hookCount = row[0].as<int64_t>();
+						if (hookCount > 0) {
+							notifyNewMember(networkId, memberId);
+						}
 					}
 					}
 
 
 					const uint64_t nwidInt = OSUtils::jsonIntHex(config["nwid"], 0ULL);
 					const uint64_t nwidInt = OSUtils::jsonIntHex(config["nwid"], 0ULL);

+ 8 - 6
ext/central-controller-docker/main.sh

@@ -100,12 +100,14 @@ else
     done
     done
 fi
 fi
 
 
-echo "Waiting for temporal"
-while ! nc -z ${ZT_TEMPORAL_HOST} ${ZT_TEMPORAL_PORT}; do
-    echo "waiting...";
-    sleep 1;
-done
-echo "Temporal is up"
+if [ -n "$ZT_TEMPORAL_HOST" ] && [ -n "$ZT_TEMPORAL_PORT" ]; then
+    echo "waiting for temporal..."
+    while ! nc -z ${ZT_TEMPORAL_HOST} ${ZT_TEMPORAL_PORT}; do
+        echo "waiting...";
+        sleep 1;
+    done
+    echo "Temporal is up"
+fi
 
 
 export GLIBCXX_FORCE_NEW=1
 export GLIBCXX_FORCE_NEW=1
 export GLIBCPP_FORCE_NEW=1
 export GLIBCPP_FORCE_NEW=1

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 416 - 92
ext/cpp-httplib/httplib.h


+ 83 - 29
node/Network.cpp

@@ -107,11 +107,22 @@ static _doZtFilterResult _doZtFilter(
 	// The default match state for each set of entries starts as 'true' since an
 	// The default match state for each set of entries starts as 'true' since an
 	// ACTION with no MATCH entries preceding it is always taken.
 	// ACTION with no MATCH entries preceding it is always taken.
 	uint8_t thisSetMatches = 1;
 	uint8_t thisSetMatches = 1;
+	uint8_t skipDrop = 0;
 
 
 	rrl.clear();
 	rrl.clear();
 
 
+	// uncomment for easier debugging fprintf
+	// if (!ztDest) { return DOZTFILTER_ACCEPT; }
+#ifdef ZT_TRACE
+	//char buf[40], buf2[40];
+	//fprintf(stderr, "\nsrc %s dest %s inbound: %d ethertype %u", ztSource.toString(buf), ztDest.toString(buf2), inbound, etherType);
+#endif
+
 	for(unsigned int rn=0;rn<ruleCount;++rn) {
 	for(unsigned int rn=0;rn<ruleCount;++rn) {
 		const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[rn].t & 0x3f);
 		const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[rn].t & 0x3f);
+#ifdef ZT_TRACE
+		//fprintf(stderr, "\n%02u %02d", rn, rt);
+#endif
 
 
 		// First check if this is an ACTION
 		// First check if this is an ACTION
 		if ((unsigned int)rt <= (unsigned int)ZT_NETWORK_RULE_ACTION__MAX_ID) {
 		if ((unsigned int)rt <= (unsigned int)ZT_NETWORK_RULE_ACTION__MAX_ID) {
@@ -121,11 +132,25 @@ static _doZtFilterResult _doZtFilter(
 						qosBucket = (rules[rn].v.qosBucket <= 8) ? rules[rn].v.qosBucket : 4; // 4 = default bucket (no priority)
 						qosBucket = (rules[rn].v.qosBucket <= 8) ? rules[rn].v.qosBucket : 4; // 4 = default bucket (no priority)
 						return DOZTFILTER_ACCEPT;
 						return DOZTFILTER_ACCEPT;
 
 
-					case ZT_NETWORK_RULE_ACTION_DROP:
+					case ZT_NETWORK_RULE_ACTION_DROP: {
+						if (!!skipDrop) {
+#ifdef ZT_TRACE
+							//fprintf(stderr, "\tskip Drop");
+#endif
+							skipDrop = 0; continue;
+						}
+#ifdef ZT_TRACE
+						//fprintf(stderr, "\tDrop\n");
+#endif
 						return DOZTFILTER_DROP;
 						return DOZTFILTER_DROP;
+					}
 
 
-					case ZT_NETWORK_RULE_ACTION_ACCEPT:
+					case ZT_NETWORK_RULE_ACTION_ACCEPT: {
+#ifdef ZT_TRACE
+						//fprintf(stderr, "\tAccept\n");
+#endif
 						return (superAccept ? DOZTFILTER_SUPER_ACCEPT : DOZTFILTER_ACCEPT); // match, accept packet
 						return (superAccept ? DOZTFILTER_SUPER_ACCEPT : DOZTFILTER_ACCEPT); // match, accept packet
+					}
 
 
 					// These are initially handled together since preliminary logic is common
 					// These are initially handled together since preliminary logic is common
 					case ZT_NETWORK_RULE_ACTION_TEE:
 					case ZT_NETWORK_RULE_ACTION_TEE:
@@ -192,6 +217,9 @@ static _doZtFilterResult _doZtFilter(
 		// If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result])
 		// If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result])
 		uint8_t thisRuleMatches = 0;
 		uint8_t thisRuleMatches = 0;
 		uint64_t ownershipVerificationMask = 1; // this magic value means it hasn't been computed yet -- this is done lazily the first time it's needed
 		uint64_t ownershipVerificationMask = 1; // this magic value means it hasn't been computed yet -- this is done lazily the first time it's needed
+		uint8_t hardYes = (rules[rn].t >> 7) ^ 1; // XOR with the NOT bit of the rule
+		uint8_t hardNo = (rules[rn].t >> 7) ^ 0;
+
 		switch(rt) {
 		switch(rt) {
 			case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
 			case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
 				thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt());
 				thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt());
@@ -220,28 +248,28 @@ static _doZtFilterResult _doZtFilter(
 				if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
 				if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
 					thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 12),4,0)));
 					thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 12),4,0)));
 				} else {
 				} else {
-					thisRuleMatches = 0;
+					thisRuleMatches = hardNo;
 				}
 				}
 				break;
 				break;
 			case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
 			case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
 				if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
 				if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
 					thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 16),4,0)));
 					thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 16),4,0)));
 				} else {
 				} else {
-					thisRuleMatches = 0;
+					thisRuleMatches = hardNo;
 				}
 				}
 				break;
 				break;
 			case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
 			case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
 				if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) {
 				if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) {
 					thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 8),16,0)));
 					thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 8),16,0)));
 				} else {
 				} else {
-					thisRuleMatches = 0;
+					thisRuleMatches = hardNo;
 				}
 				}
 				break;
 				break;
 			case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
 			case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
 				if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) {
 				if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) {
 					thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 24),16,0)));
 					thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 24),16,0)));
 				} else {
 				} else {
-					thisRuleMatches = 0;
+					thisRuleMatches = hardNo;
 				}
 				}
 				break;
 				break;
 			case ZT_NETWORK_RULE_MATCH_IP_TOS:
 			case ZT_NETWORK_RULE_MATCH_IP_TOS:
@@ -252,7 +280,7 @@ static _doZtFilterResult _doZtFilter(
 					const uint8_t tosMasked = (((frameData[0] << 4) & 0xf0) | ((frameData[1] >> 4) & 0x0f)) & rules[rn].v.ipTos.mask;
 					const uint8_t tosMasked = (((frameData[0] << 4) & 0xf0) | ((frameData[1] >> 4) & 0x0f)) & rules[rn].v.ipTos.mask;
 					thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1]));
 					thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1]));
 				} else {
 				} else {
-					thisRuleMatches = 0;
+					thisRuleMatches = hardNo;
 				}
 				}
 				break;
 				break;
 			case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
 			case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
@@ -263,10 +291,10 @@ static _doZtFilterResult _doZtFilter(
 					if (_ipv6GetPayload(frameData,frameLen,pos,proto)) {
 					if (_ipv6GetPayload(frameData,frameLen,pos,proto)) {
 						thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == (uint8_t)proto);
 						thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == (uint8_t)proto);
 					} else {
 					} else {
-						thisRuleMatches = 0;
+						thisRuleMatches = hardNo;
 					}
 					}
 				} else {
 				} else {
-					thisRuleMatches = 0;
+					thisRuleMatches = hardNo;
 				}
 				}
 				break;
 				break;
 			case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
 			case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
@@ -281,16 +309,16 @@ static _doZtFilterResult _doZtFilter(
 								if ((rules[rn].v.icmp.flags & 0x01) != 0) {
 								if ((rules[rn].v.icmp.flags & 0x01) != 0) {
 									thisRuleMatches = (uint8_t)(frameData[ihl+1] == rules[rn].v.icmp.code);
 									thisRuleMatches = (uint8_t)(frameData[ihl+1] == rules[rn].v.icmp.code);
 								} else {
 								} else {
-									thisRuleMatches = 1;
+									thisRuleMatches = hardYes;
 								}
 								}
 							} else {
 							} else {
-								thisRuleMatches = 0;
+								thisRuleMatches = hardNo;
 							}
 							}
 						} else {
 						} else {
-							thisRuleMatches = 0;
+							thisRuleMatches = hardNo;
 						}
 						}
 					} else {
 					} else {
-						thisRuleMatches = 0;
+						thisRuleMatches = hardNo;
 					}
 					}
 				} else if (etherType == ZT_ETHERTYPE_IPV6) {
 				} else if (etherType == ZT_ETHERTYPE_IPV6) {
 					unsigned int pos = 0,proto = 0;
 					unsigned int pos = 0,proto = 0;
@@ -300,19 +328,19 @@ static _doZtFilterResult _doZtFilter(
 								if ((rules[rn].v.icmp.flags & 0x01) != 0) {
 								if ((rules[rn].v.icmp.flags & 0x01) != 0) {
 									thisRuleMatches = (uint8_t)(frameData[pos+1] == rules[rn].v.icmp.code);
 									thisRuleMatches = (uint8_t)(frameData[pos+1] == rules[rn].v.icmp.code);
 								} else {
 								} else {
-									thisRuleMatches = 1;
+									thisRuleMatches = hardYes;
 								}
 								}
 							} else {
 							} else {
-								thisRuleMatches = 0;
+								thisRuleMatches = hardNo;
 							}
 							}
 						} else {
 						} else {
-							thisRuleMatches = 0;
+							thisRuleMatches = hardNo;
 						}
 						}
 					} else {
 					} else {
-						thisRuleMatches = 0;
+						thisRuleMatches = hardNo;
 					}
 					}
 				} else {
 				} else {
-					thisRuleMatches = 0;
+					thisRuleMatches = hardNo;
 				}
 				}
 				break;
 				break;
 			case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
 			case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
@@ -356,10 +384,10 @@ static _doZtFilterResult _doZtFilter(
 						}
 						}
 						thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0;
 						thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0;
 					} else {
 					} else {
-						thisRuleMatches = 0;
+						thisRuleMatches = hardNo;
 					}
 					}
 				} else {
 				} else {
-					thisRuleMatches = 0;
+					thisRuleMatches = hardNo;
 				}
 				}
 				break;
 				break;
 			case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: {
 			case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: {
@@ -444,6 +472,14 @@ static _doZtFilterResult _doZtFilter(
 				const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate());
 				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)) {
 				if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) {
 					const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0);
 					const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0);
+#ifdef ZT_TRACE
+					/*fprintf(stderr, "\tlocal tag [%u: %u] remote tag [%u: %u] match [%u]",
+							!!localTag ? localTag->id() : 0,
+							!!localTag ? localTag->value() : 0,
+							!!remoteTag ? remoteTag->id() : 0,
+							!!remoteTag ? remoteTag->value() : 0,
+							thisRuleMatches);*/
+#endif
 					if (remoteTag) {
 					if (remoteTag) {
 						const uint32_t ltv = localTag->value();
 						const uint32_t ltv = localTag->value();
 						const uint32_t rtv = remoteTag->value();
 						const uint32_t rtv = remoteTag->value();
@@ -459,28 +495,46 @@ static _doZtFilterResult _doZtFilter(
 						} else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_EQUAL) {
 						} else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_EQUAL) {
 							thisRuleMatches = (uint8_t)((ltv == rules[rn].v.tag.value)&&(rtv == rules[rn].v.tag.value));
 							thisRuleMatches = (uint8_t)((ltv == rules[rn].v.tag.value)&&(rtv == rules[rn].v.tag.value));
 						} else { // sanity check, can't really happen
 						} else { // sanity check, can't really happen
-							thisRuleMatches = 0;
+							thisRuleMatches = hardNo;
 						}
 						}
 					} else {
 					} else {
 						if ((inbound)&&(!superAccept)) {
 						if ((inbound)&&(!superAccept)) {
-							thisRuleMatches = 0;
+							thisRuleMatches = hardNo;
+#ifdef ZT_TRACE
+							//fprintf(stderr, "\tinbound ");
+#endif
 						} else {
 						} else {
 							// Outbound side is not strict since if we have to match both tags and
 							// 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
 							// 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
 							// 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
 							// 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.
 							// not strict since we likely do not have these tags.
-							thisRuleMatches = 1;
+							skipDrop = 1;
+							thisRuleMatches = hardYes;
+#ifdef ZT_TRACE
+							//fprintf(stderr, "\toutbound ");
+#endif
 						}
 						}
 					}
 					}
 				} else {
 				} else {
-					thisRuleMatches = 0;
+					thisRuleMatches = hardNo;
 				}
 				}
 			}	break;
 			}	break;
 			case ZT_NETWORK_RULE_MATCH_TAG_SENDER:
 			case ZT_NETWORK_RULE_MATCH_TAG_SENDER:
 			case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: {
 			case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: {
+					const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate());
+#ifdef ZT_TRACE
+					/*const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0);
+					fprintf(stderr, "\tlocal tag [%u: %u] remote tag [%u: %u] match [%u]",
+							!!localTag ? localTag->id() : 0,
+							!!localTag ? localTag->value() : 0,
+							!!remoteTag ? remoteTag->id() : 0,
+							!!remoteTag ? remoteTag->value() : 0,
+							thisRuleMatches);*/
+#endif
 				if (superAccept) {
 				if (superAccept) {
-					thisRuleMatches = 1;
+					skipDrop = 1;
+					thisRuleMatches = hardYes;
 				} else if ( ((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER)&&(inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER)&&(!inbound)) ) {
 				} 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);
 					const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0);
 					if (remoteTag) {
 					if (remoteTag) {
@@ -489,17 +543,17 @@ static _doZtFilterResult _doZtFilter(
 						if (rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) {
 						if (rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) {
 							// If we are checking the receiver and this is an outbound packet, we
 							// 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.
 							// can't be strict since we may not yet know the receiver's tag.
-							thisRuleMatches = 1;
+							skipDrop = 1;
+							thisRuleMatches = hardYes;
 						} else {
 						} else {
-							thisRuleMatches = 0;
+							thisRuleMatches = hardNo;
 						}
 						}
 					}
 					}
 				} else { // sender and outbound or receiver and inbound
 				} 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)) {
 					if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) {
 						thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value);
 						thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value);
 					} else {
 					} else {
-						thisRuleMatches = 0;
+						thisRuleMatches = hardNo;
 					}
 					}
 				}
 				}
 			}	break;
 			}	break;

+ 16 - 15
service/OneService.cpp

@@ -1172,25 +1172,25 @@ public:
 					}
 					}
 				}
 				}
 
 
-				// If secondary port is not configured to a constant value and we've been offline for a while,
-				// bind a new secondary port. This is a workaround for a "coma" issue caused by buggy NATs that stop
-				// working on one port after a while.
-				if (_secondaryPort == 0) {
-					if (_node->online()) {
-						lastOnline = now;
-					}
-					if ((now - lastOnline) > ZT_PATH_HEARTBEAT_PERIOD  || restarted) {
-						_ports[1] = _getRandomPort();
+				// Refresh bindings in case device's interfaces have changed, and also sync routes to update any shadow routes (e.g. shadow default)
+				if (((now - lastBindRefresh) >= (_node->bondController()->inUse() ? ZT_BINDER_REFRESH_PERIOD / 4 : ZT_BINDER_REFRESH_PERIOD))||restarted) {
+					// If secondary port is not configured to a constant value and we've been offline for a while,
+					// bind a new secondary port. This is a workaround for a "coma" issue caused by buggy NATs that stop
+					// working on one port after a while.
+					if (_secondaryPort == 0) {
+						if (_node->online()) {
+							lastOnline = now;
+						}
+						else if (now - lastOnline > (ZT_PEER_PING_PERIOD * 2) || restarted) {
+							lastOnline = now;	// don't keep changing the port before we have a chance to connect
+							_ports[1] = _getRandomPort();
+
 #if ZT_DEBUG==1
 #if ZT_DEBUG==1
-						fprintf(stderr, "randomized secondary port. Now it's %d\n", _ports[1]);
+							fprintf(stderr, "Randomized secondary port. Now it's %d\n", _ports[1]);
 #endif
 #endif
-						lastOnline = now; // don't keep spamming this branch. online() will be false for a few seconds
+						}
 					}
 					}
-				}
-
 
 
-				// Refresh bindings in case device's interfaces have changed, and also sync routes to update any shadow routes (e.g. shadow default)
-				if (((now - lastBindRefresh) >= (_node->bondController()->inUse() ? ZT_BINDER_REFRESH_PERIOD / 4 : ZT_BINDER_REFRESH_PERIOD))||restarted) {
 					unsigned int p[3];
 					unsigned int p[3];
 					unsigned int pc = 0;
 					unsigned int pc = 0;
 					for(int i=0;i<3;++i) {
 					for(int i=0;i<3;++i) {
@@ -2041,6 +2041,7 @@ public:
             settings["primaryPort"] = OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff;
             settings["primaryPort"] = OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff;
             settings["secondaryPort"] = OSUtils::jsonInt(settings["secondaryPort"],(uint64_t)_ports[1]) & 0xffff;
             settings["secondaryPort"] = OSUtils::jsonInt(settings["secondaryPort"],(uint64_t)_ports[1]) & 0xffff;
             settings["tertiaryPort"] = OSUtils::jsonInt(settings["tertiaryPort"],(uint64_t)_tertiaryPort) & 0xffff;
             settings["tertiaryPort"] = OSUtils::jsonInt(settings["tertiaryPort"],(uint64_t)_tertiaryPort) & 0xffff;
+            settings["homeDir"] = _homePath;
             // Enumerate all local address/port pairs that this node is listening on
             // Enumerate all local address/port pairs that this node is listening on
             std::vector<InetAddress> boundAddrs(_binder.allBoundLocalInterfaceAddresses());
             std::vector<InetAddress> boundAddrs(_binder.allBoundLocalInterfaceAddresses());
             auto boundAddrArray = json::array();
             auto boundAddrArray = json::array();

+ 1 - 1
tcp-proxy/Makefile

@@ -3,7 +3,7 @@ CXX=$(shell which clang++ g++ c++ 2>/dev/null | head -n 1)
 INCLUDES?=-I../ext/prometheus-cpp-lite-1.0/core/include  -I../ext/prometheus-cpp-lite-1.0/simpleapi/include
 INCLUDES?=-I../ext/prometheus-cpp-lite-1.0/core/include  -I../ext/prometheus-cpp-lite-1.0/simpleapi/include
 
 
 all:
 all:
-	$(CXX) -O3 -fno-rtti $(INCLUDES) -std=c++11 -frtti  -o tcp-proxy tcp-proxy.cpp ../node/Metrics.cpp
+	$(CXX) -O3 -fno-rtti $(INCLUDES) -std=c++11 -pthread -frtti  -o tcp-proxy tcp-proxy.cpp ../node/Metrics.cpp
 
 
 clean:
 clean:
 	rm -f *.o tcp-proxy *.dSYM
 	rm -f *.o tcp-proxy *.dSYM

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است