summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--controller/EmbeddedNetworkController.cpp67
-rw-r--r--controller/EmbeddedNetworkController.hpp4
-rw-r--r--include/ZeroTierOne.h45
-rw-r--r--node/IncomingPacket.cpp27
-rw-r--r--node/IncomingPacket.hpp1
-rw-r--r--node/Packet.hpp3
-rw-r--r--service/OneService.cpp6
7 files changed, 148 insertions, 5 deletions
diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp
index b57a37e8..8b8a93bd 100644
--- a/controller/EmbeddedNetworkController.cpp
+++ b/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("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")) {
const bool newAuth = OSUtils::jsonBool(b["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("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")) {
json nv4m;
json &v4m = b["v4AssignMode"];
@@ -1065,6 +1083,55 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE(
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()
throw()
{
diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp
index 1589ea71..03ba0b95 100644
--- a/controller/EmbeddedNetworkController.hpp
+++ b/controller/EmbeddedNetworkController.hpp
@@ -90,6 +90,8 @@ public:
std::string &responseBody,
std::string &responseContentType);
+ void handleRemoteTrace(const ZT_RemoteTrace &rt);
+
void threadMain()
throw();
@@ -142,6 +144,7 @@ private:
if (!member.count("vRev")) member["vRev"] = -1;
if (!member.count("vProto")) member["vProto"] = -1;
if (!member.count("physicalAddr")) member["physicalAddr"] = nlohmann::json();
+ if (!member.count("remoteTraceTarget")) member["remoteTraceTarget"] = nlohmann::json();
member["objtype"] = "member";
}
inline void _initNetwork(nlohmann::json &network)
@@ -159,6 +162,7 @@ private:
if (!network.count("routes")) network["routes"] = nlohmann::json::array();
if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array();
if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU;
+ if (!network.count("remoteTraceTarget")) network["remoteTraceTarget"] = nlohmann::json();
if (!network.count("rules")) {
// If unspecified, rules are set to allow anything and behave like a flat L2 segment
network["rules"] = {{
diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h
index e4c39fbc..14ddc7fe 100644
--- a/include/ZeroTierOne.h
+++ b/include/ZeroTierOne.h
@@ -470,10 +470,53 @@ enum ZT_Event
*
* 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
*
* These are direct VL1 P2P messages for application use. Encryption and
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index a5875d1e..5e5d1d72 100644
--- a/node/IncomingPacket.cpp
+++ b/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)
{
try {
- if (size() >= (ZT_PACKET_IDX_PAYLOAD + 8)) {
+ if (likely(size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) {
ZT_UserMessage um;
um.origin = peer->address().toInt();
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;
}
+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)
{
const uint64_t now = RR->node->now();
diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp
index 11b60712..692c63df 100644
--- a/node/IncomingPacket.hpp
+++ b/node/IncomingPacket.hpp
@@ -139,6 +139,7 @@ private:
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 _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);
diff --git a/node/Packet.hpp b/node/Packet.hpp
index a1ea73e1..b8e69fa9 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -978,9 +978,6 @@ public:
* The instance ID is a random 64-bit value generated by each ZeroTier
* node on startup. This is helpful in identifying traces from different
* 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
};
diff --git a/service/OneService.cpp b/service/OneService.cpp
index 1b07eb79..115830e5 100644
--- a/service/OneService.cpp
+++ b/service/OneService.cpp
@@ -2058,6 +2058,12 @@ public:
}
} 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:
break;
}