Plumbing through of remote trace into controller code.

This commit is contained in:
Adam Ierymenko 2017-07-14 13:03:16 -07:00
parent 0655a1fcbe
commit 4ecc0c59ca
7 changed files with 148 additions and 5 deletions

View File

@ -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()
{

View File

@ -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"] = {{

View File

@ -470,9 +470,52 @@ 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
*

View File

@ -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();

View File

@ -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);

View File

@ -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
};

View File

@ -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;
}