Browse Source

Plumbing through of remote trace into controller code.

Adam Ierymenko 8 years ago
parent
commit
4ecc0c59ca

+ 67 - 0
controller/EmbeddedNetworkController.cpp

@@ -621,6 +621,15 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
 						if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"],false);
 						if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"],false);
 						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("remoteTraceTarget")) {
+							const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],""));
+							if (rtt.length() == 10) {
+								member["remoteTraceTarget"] = rtt;
+							} else {
+								member["remoteTraceTarget"] = json();
+							}
+						}
+
 						if (b.count("authorized")) {
 						if (b.count("authorized")) {
 							const bool newAuth = OSUtils::jsonBool(b["authorized"],false);
 							const bool newAuth = OSUtils::jsonBool(b["authorized"],false);
 							if (newAuth != OSUtils::jsonBool(member["authorized"],false)) {
 							if (newAuth != OSUtils::jsonBool(member["authorized"],false)) {
@@ -764,6 +773,15 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
 					if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL);
 					if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL);
 					if (b.count("mtu")) network["mtu"] = std::max(std::min((unsigned int)OSUtils::jsonInt(b["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU);
 					if (b.count("mtu")) network["mtu"] = std::max(std::min((unsigned int)OSUtils::jsonInt(b["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU);
 
 
+					if (b.count("remoteTraceTarget")) {
+						const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],""));
+						if (rtt.length() == 10) {
+							network["remoteTraceTarget"] = rtt;
+						} else {
+							network["remoteTraceTarget"] = json();
+						}
+					}
+
 					if (b.count("v4AssignMode")) {
 					if (b.count("v4AssignMode")) {
 						json nv4m;
 						json nv4m;
 						json &v4m = b["v4AssignMode"];
 						json &v4m = b["v4AssignMode"];
@@ -1065,6 +1083,55 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE(
 	return 404;
 	return 404;
 }
 }
 
 
+void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt)
+{
+	// Convert Dictionary into JSON object
+	json d;
+	char *saveptr = (char *)0;
+	for(char *l=Utils::stok(rt.data,"\n",&saveptr);(l);l=Utils::stok((char *)0,"\n",&saveptr)) {
+		char *eq = strchr(l,'=');
+		if (eq > l) {
+			std::string k(l,(unsigned long)(eq - l));
+			std::string v;
+			++eq;
+			while (*eq) {
+				if (*eq == '\\') {
+					++eq;
+					if (*eq) {
+						switch(*eq) {
+							case 'r':
+								v.push_back('\r');
+								break;
+							case 'n':
+								v.push_back('\n');
+								break;
+							case '0':
+								v.push_back((char)0);
+								break;
+							case 'e':
+								v.push_back('=');
+								break;
+							default:
+								v.push_back(*eq);
+								break;
+						}
+						++eq;
+					}
+				} else {
+					v.push_back(*(eq++));
+				}
+			}
+			if (v.length() > 0)
+				d[k] = v;
+		}
+	}
+
+	char p[128];
+	OSUtils::ztsnprintf(p,sizeof(p),"trace/%.10llx_%.16llx.json",rt.origin,OSUtils::now());
+	_db.writeRaw(p,OSUtils::jsonDump(d));
+	//fprintf(stdout,"%s\n",OSUtils::jsonDump(d).c_str()); fflush(stdout);
+}
+
 void EmbeddedNetworkController::threadMain()
 void EmbeddedNetworkController::threadMain()
 	throw()
 	throw()
 {
 {

+ 4 - 0
controller/EmbeddedNetworkController.hpp

@@ -90,6 +90,8 @@ public:
 		std::string &responseBody,
 		std::string &responseBody,
 		std::string &responseContentType);
 		std::string &responseContentType);
 
 
+	void handleRemoteTrace(const ZT_RemoteTrace &rt);
+
 	void threadMain()
 	void threadMain()
 		throw();
 		throw();
 
 
@@ -142,6 +144,7 @@ private:
 		if (!member.count("vRev")) member["vRev"] = -1;
 		if (!member.count("vRev")) member["vRev"] = -1;
 		if (!member.count("vProto")) member["vProto"] = -1;
 		if (!member.count("vProto")) member["vProto"] = -1;
 		if (!member.count("physicalAddr")) member["physicalAddr"] = nlohmann::json();
 		if (!member.count("physicalAddr")) member["physicalAddr"] = nlohmann::json();
+		if (!member.count("remoteTraceTarget")) member["remoteTraceTarget"] = nlohmann::json();
 		member["objtype"] = "member";
 		member["objtype"] = "member";
 	}
 	}
 	inline void _initNetwork(nlohmann::json &network)
 	inline void _initNetwork(nlohmann::json &network)
@@ -159,6 +162,7 @@ private:
 		if (!network.count("routes")) network["routes"] = nlohmann::json::array();
 		if (!network.count("routes")) network["routes"] = nlohmann::json::array();
 		if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array();
 		if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array();
 		if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU;
 		if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU;
+		if (!network.count("remoteTraceTarget")) network["remoteTraceTarget"] = nlohmann::json();
 		if (!network.count("rules")) {
 		if (!network.count("rules")) {
 			// If unspecified, rules are set to allow anything and behave like a flat L2 segment
 			// If unspecified, rules are set to allow anything and behave like a flat L2 segment
 			network["rules"] = {{
 			network["rules"] = {{

+ 44 - 1
include/ZeroTierOne.h

@@ -470,9 +470,52 @@ enum ZT_Event
 	 *
 	 *
 	 * Meta-data: ZT_UserMessage structure
 	 * Meta-data: ZT_UserMessage structure
 	 */
 	 */
-	ZT_EVENT_USER_MESSAGE = 6
+	ZT_EVENT_USER_MESSAGE = 6,
+
+	/**
+	 * Remote trace received
+	 *
+	 * These are generated when a VERB_REMOTE_TRACE is received. Note
+	 * that any node can fling one of these at us. It is your responsibility
+	 * to filter and determine if it's worth paying attention to. If it's
+	 * not just drop it. Most nodes that are not active controllers ignore
+	 * these, and controllers only save them if they pertain to networks
+	 * with remote tracing enabled.
+	 *
+	 * Meta-data: ZT_RemoteTrace structure
+	 */
+	ZT_EVENT_REMOTE_TRACE = 7
 };
 };
 
 
+/**
+ * Payload of REMOTE_TRACE event
+ */
+typedef struct
+{
+	/**
+	 * ZeroTier address of sender
+	 */
+	uint64_t origin;
+
+	/**
+	 * Null-terminated Dictionary containing key/value pairs sent by origin
+	 *
+	 * This *should* be a dictionary, but the implementation only checks
+	 * that it is a valid non-empty C-style null-terminated string. Be very
+	 * careful to use a well-tested parser to parse this as it represents
+	 * data received from a potentially un-trusted peer on the network.
+	 * Invalid payloads should be dropped.
+	 *
+	 * The contents of data[] may be modified.
+	 */
+	char *data;
+
+	/**
+	 * Length of dict[] in bytes, including terminating null
+	 */
+	unsigned int len;
+} ZT_RemoteTrace;
+
 /**
 /**
  * User message used with ZT_EVENT_USER_MESSAGE
  * User message used with ZT_EVENT_USER_MESSAGE
  *
  *

+ 26 - 1
node/IncomingPacket.cpp

@@ -1192,7 +1192,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
 bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
 bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
 {
 {
 	try {
 	try {
-		if (size() >= (ZT_PACKET_IDX_PAYLOAD + 8)) {
+		if (likely(size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) {
 			ZT_UserMessage um;
 			ZT_UserMessage um;
 			um.origin = peer->address().toInt();
 			um.origin = peer->address().toInt();
 			um.typeId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD);
 			um.typeId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD);
@@ -1207,6 +1207,31 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,con
 	return true;
 	return true;
 }
 }
 
 
+bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
+{
+	ZT_RemoteTrace rt;
+	try {
+		const char *ptr = reinterpret_cast<const char *>(data()) + ZT_PACKET_IDX_PAYLOAD;
+		const char *const eof = reinterpret_cast<const char *>(data()) + size();
+		rt.origin = peer->address().toInt();
+		rt.data = const_cast<char *>(ptr); // start of first string
+		while (ptr < eof) {
+			if (!*ptr) { // end of string
+				rt.len = (unsigned int)(ptr - rt.data);
+				if ((rt.len > 0)&&(rt.len <= ZT_MAX_REMOTE_TRACE_SIZE))
+					RR->node->postEvent(tPtr,ZT_EVENT_REMOTE_TRACE,&rt);
+				rt.data = const_cast<char *>(++ptr); // start of next string, if any
+			} else {
+				++ptr;
+			}
+		}
+		peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_REMOTE_TRACE,0,Packet::VERB_NOP,false,0);
+	} catch ( ... ) {
+		RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_REMOTE_TRACE,"unexpected exception");
+	}
+	return true;
+}
+
 void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid)
 void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid)
 {
 {
 	const uint64_t now = RR->node->now();
 	const uint64_t now = RR->node->now();

+ 1 - 0
node/IncomingPacket.hpp

@@ -139,6 +139,7 @@ private:
 	bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
 	bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
 	bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
 	bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
 	bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
 	bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
+	bool _doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
 
 
 	void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid);
 	void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid);
 
 

+ 0 - 3
node/Packet.hpp

@@ -978,9 +978,6 @@ public:
 		 * The instance ID is a random 64-bit value generated by each ZeroTier
 		 * The instance ID is a random 64-bit value generated by each ZeroTier
 		 * node on startup. This is helpful in identifying traces from different
 		 * node on startup. This is helpful in identifying traces from different
 		 * members of a cluster.
 		 * members of a cluster.
-		 *
-		 * The Dictionary serialization format is the same as used for network
-		 * configurations. The maximum size of a trace is 10000 bytes.
 		 */
 		 */
 		VERB_REMOTE_TRACE = 0x15
 		VERB_REMOTE_TRACE = 0x15
 	};
 	};

+ 6 - 0
service/OneService.cpp

@@ -2058,6 +2058,12 @@ public:
 				}
 				}
 			}	break;
 			}	break;
 
 
+			case ZT_EVENT_REMOTE_TRACE: {
+				const ZT_RemoteTrace *rt = reinterpret_cast<const ZT_RemoteTrace *>(metaData);
+				if ((rt)&&(rt->len > 0)&&(rt->len <= ZT_MAX_REMOTE_TRACE_SIZE)&&(rt->data))
+					_controller->handleRemoteTrace(*rt);
+			}
+
 			default:
 			default:
 				break;
 				break;
 		}
 		}