Add length limit to TEE and REDIRECT, and completely factor out old C json-parser to eliminate a dependency.

This commit is contained in:
Adam Ierymenko 2016-08-24 13:37:57 -07:00
parent 8d594f8b53
commit 8e3463d47a
16 changed files with 158 additions and 1667 deletions

View File

@ -39,11 +39,11 @@ These are included in ext/ for platforms that do not have them available in comm
* Home page: https://github.com/joyent/http-parser/
* License grant: MIT/Expat
* json-parser by James McLaughlin
* C++11 json (nlohmann/json) by Niels Lohmann
* Files: ext/json-parser/*
* Home page: https://github.com/udp/json-parser/
* License grant: BSD attribution
* Files: ext/json/*
* Home page: https://github.com/nlohmann/json
* License grant: MIT
* TunTapOSX by Mattias Nissler

View File

@ -121,11 +121,15 @@ static json _renderRule(ZT_VirtualNetworkRule &rule)
break;
case ZT_NETWORK_RULE_ACTION_TEE:
r["type"] = "ACTION_TEE";
r["zt"] = Address(rule.v.zt).toString();
r["address"] = Address(rule.v.fwd.address).toString();
r["flags"] = (uint64_t)rule.v.fwd.flags;
r["length"] = (uint64_t)rule.v.fwd.length;
break;
case ZT_NETWORK_RULE_ACTION_REDIRECT:
r["type"] = "ACTION_REDIRECT";
r["zt"] = Address(rule.v.zt).toString();
r["address"] = Address(rule.v.fwd.address).toString();
r["flags"] = (uint64_t)rule.v.fwd.flags;
r["length"] = (uint64_t)rule.v.fwd.length;
break;
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
r["type"] = "MATCH_SOURCE_ZEROTIER_ADDRESS";
@ -235,7 +239,7 @@ static bool _parseRule(const json &r,ZT_VirtualNetworkRule &rule)
{
if (r.is_object())
return false;
std::string t = r["type"];
const std::string t(_jS(r["type"],""));
memset(&rule,0,sizeof(ZT_VirtualNetworkRule));
if (_jB(r["not"],false))
rule.t = 0x80;
@ -248,11 +252,15 @@ static bool _parseRule(const json &r,ZT_VirtualNetworkRule &rule)
return true;
} else if (t == "ACTION_TEE") {
rule.t |= ZT_NETWORK_RULE_ACTION_TEE;
rule.v.zt = Utils::hexStrToU64(_jS(r["zt"],"0").c_str()) & 0xffffffffffULL;
rule.v.fwd.address = Utils::hexStrToU64(_jS(r["address"],"0").c_str()) & 0xffffffffffULL;
rule.v.fwd.flags = (uint32_t)(_jI(r["flags"],0ULL) & 0xffffffffULL);
rule.v.fwd.length = (uint16_t)(_jI(r["length"],0ULL) & 0xffffULL);
return true;
} else if (t == "ACTION_REDIRECT") {
rule.t |= ZT_NETWORK_RULE_ACTION_REDIRECT;
rule.v.zt = Utils::hexStrToU64(_jS(r["zt"],"0").c_str()) & 0xffffffffffULL;
rule.v.fwd.address = Utils::hexStrToU64(_jS(r["zt"],"0").c_str()) & 0xffffffffffULL;
rule.v.fwd.flags = (uint32_t)(_jI(r["flags"],0ULL) & 0xffffffffULL);
rule.v.fwd.length = (uint16_t)(_jI(r["length"],0ULL) & 0xffffULL);
return true;
} else if (t == "MATCH_SOURCE_ZEROTIER_ADDRESS") {
rule.t |= ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS;

View File

@ -1,20 +0,0 @@
All contributors arranged by first commit:
James McLaughlin
Alex Gartrell
Peter Scott
Mathias Kaerlev
Emiel Mols
Czarek Tomczak
Nicholas Braden
Ivan Kozub
Árpád Goretity
Igor Gnatenko
Haïkel Guémar
Tobias Waldekranz
Patrick Donnelly
Wilmer van der Gaast
Jin Wei
François Cartegnie
Matthijs Boelstra

View File

@ -1,26 +0,0 @@
Copyright (C) 2012, 2013 James McLaughlin et al. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

View File

@ -1,97 +0,0 @@
Very low footprint JSON parser written in portable ANSI C.
* BSD licensed with no dependencies (i.e. just drop the C file into your project)
* Never recurses or allocates more memory than it needs
* Very simple API with operator sugar for C++
[![Build Status](https://secure.travis-ci.org/udp/json-parser.png)](http://travis-ci.org/udp/json-parser)
_Want to serialize? Check out [json-builder](https://github.com/udp/json-builder)!_
Installing
----------
There is now a makefile which will produce a libjsonparser static and dynamic library. However, this
is _not_ required to build json-parser, and the source files (`json.c` and `json.h`) should be happy
in any build system you already have in place.
API
---
json_value * json_parse (const json_char * json,
size_t length);
json_value * json_parse_ex (json_settings * settings,
const json_char * json,
size_t length,
char * error);
void json_value_free (json_value *);
The `type` field of `json_value` is one of:
* `json_object` (see `u.object.length`, `u.object.values[x].name`, `u.object.values[x].value`)
* `json_array` (see `u.array.length`, `u.array.values`)
* `json_integer` (see `u.integer`)
* `json_double` (see `u.dbl`)
* `json_string` (see `u.string.ptr`, `u.string.length`)
* `json_boolean` (see `u.boolean`)
* `json_null`
Compile-Time Options
--------------------
-DJSON_TRACK_SOURCE
Stores the source location (line and column number) inside each `json_value`.
This is useful for application-level error reporting.
Runtime Options
---------------
settings |= json_enable_comments;
Enables C-style `// line` and `/* block */` comments.
size_t value_extra
The amount of space (if any) to allocate at the end of each `json_value`, in
order to give the application space to add metadata.
void * (* mem_alloc) (size_t, int zero, void * user_data);
void (* mem_free) (void *, void * user_data);
Custom allocator routines. If NULL, the default `malloc` and `free` will be used.
The `user_data` pointer will be forwarded from `json_settings` to allow application
context to be passed.
Changes in version 1.1.0
------------------------
* UTF-8 byte order marks are now skipped if present
* Allows cross-compilation by honoring --host if given (@wkz)
* Maximum size for error buffer is now exposed in header (@LB--)
* GCC warning for `static` after `const` fixed (@batrick)
* Optional support for C-style line and block comments added (@Jin-W-FS)
* `name_length` field added to object values
* It is now possible to retrieve the source line/column number of a parsed `json_value` when `JSON_TRACK_SOURCE` is enabled
* The application may now extend `json_value` using the `value_extra` setting
* Un-ambiguate pow call in the case of C++ overloaded pow (@fcartegnie)
* Fix null pointer de-reference when a non-existing array is closed and no root value is present

File diff suppressed because it is too large Load Diff

View File

@ -1,283 +0,0 @@
/* vim: set et ts=3 sw=3 sts=3 ft=c:
*
* Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
* https://github.com/udp/json-parser
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _JSON_H
#define _JSON_H
#ifndef json_char
#define json_char char
#endif
#ifndef json_int_t
#ifndef _MSC_VER
#include <inttypes.h>
#define json_int_t int64_t
#else
#define json_int_t __int64
#endif
#endif
#include <stdlib.h>
#ifdef __cplusplus
#include <string.h>
extern "C"
{
#endif
typedef struct
{
unsigned long max_memory;
int settings;
/* Custom allocator support (leave null to use malloc/free)
*/
void * (* mem_alloc) (size_t, int zero, void * user_data);
void (* mem_free) (void *, void * user_data);
void * user_data; /* will be passed to mem_alloc and mem_free */
size_t value_extra; /* how much extra space to allocate for values? */
} json_settings;
#define json_enable_comments 0x01
typedef enum
{
json_none,
json_object,
json_array,
json_integer,
json_double,
json_string,
json_boolean,
json_null
} json_type;
extern const struct _json_value json_value_none;
typedef struct _json_object_entry
{
json_char * name;
unsigned int name_length;
struct _json_value * value;
} json_object_entry;
typedef struct _json_value
{
struct _json_value * parent;
json_type type;
union
{
int boolean;
json_int_t integer;
double dbl;
struct
{
unsigned int length;
json_char * ptr; /* null terminated */
} string;
struct
{
unsigned int length;
json_object_entry * values;
#if defined(__cplusplus) && __cplusplus >= 201103L
decltype(values) begin () const
{ return values;
}
decltype(values) end () const
{ return values + length;
}
#endif
} object;
struct
{
unsigned int length;
struct _json_value ** values;
#if defined(__cplusplus) && __cplusplus >= 201103L
decltype(values) begin () const
{ return values;
}
decltype(values) end () const
{ return values + length;
}
#endif
} array;
} u;
union
{
struct _json_value * next_alloc;
void * object_mem;
} _reserved;
#ifdef JSON_TRACK_SOURCE
/* Location of the value in the source JSON
*/
unsigned int line, col;
#endif
/* Some C++ operator sugar */
#ifdef __cplusplus
public:
inline _json_value ()
{ memset (this, 0, sizeof (_json_value));
}
inline const struct _json_value &operator [] (int index) const
{
if (type != json_array || index < 0
|| ((unsigned int) index) >= u.array.length)
{
return json_value_none;
}
return *u.array.values [index];
}
inline const struct _json_value &operator [] (const char * index) const
{
if (type != json_object)
return json_value_none;
for (unsigned int i = 0; i < u.object.length; ++ i)
if (!strcmp (u.object.values [i].name, index))
return *u.object.values [i].value;
return json_value_none;
}
inline operator const char * () const
{
switch (type)
{
case json_string:
return u.string.ptr;
default:
return "";
};
}
inline operator json_int_t () const
{
switch (type)
{
case json_integer:
return u.integer;
case json_double:
return (json_int_t) u.dbl;
default:
return 0;
};
}
inline operator bool () const
{
if (type != json_boolean)
return false;
return u.boolean != 0;
}
inline operator double () const
{
switch (type)
{
case json_integer:
return (double) u.integer;
case json_double:
return u.dbl;
default:
return 0;
};
}
#endif
} json_value;
json_value * json_parse (const json_char * json,
size_t length);
#define json_error_max 128
json_value * json_parse_ex (json_settings * settings,
const json_char * json,
size_t length,
char * error);
void json_value_free (json_value *);
/* Not usually necessary, unless you used a custom mem_alloc and now want to
* use a custom mem_free.
*/
void json_value_free_ex (json_settings * settings,
json_value *);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@ -468,6 +468,11 @@ enum ZT_VirtualNetworkType
ZT_NETWORK_TYPE_PUBLIC = 1
};
/*
- TEE : should use a field to indicate how many bytes of each packet max are TEE'd
- Controller : web hooks for auth, optional required re-auth? or auth for a period of time? auto-expiring auth?
*/
/**
* The type of a virtual network rules table entry
*
@ -721,6 +726,15 @@ typedef struct
uint32_t id;
uint32_t value;
} tag;
/**
* Destinations for TEE and REDIRECT
*/
struct {
uint64_t address;
uint32_t flags;
uint16_t length;
} fwd;
} v;
} ZT_VirtualNetworkRule;

View File

@ -6,7 +6,7 @@ DEFS=
LIBS=
include objects.mk
OBJS+=osdep/BSDEthernetTap.o ext/lz4/lz4.o ext/json-parser/json.o ext/http-parser/http_parser.o
OBJS+=osdep/BSDEthernetTap.o ext/lz4/lz4.o ext/http-parser/http_parser.o
# "make official" is a shortcut for this
ifeq ($(ZT_OFFICIAL_RELEASE),1)

View File

@ -51,12 +51,6 @@ else
LDLIBS+=-lhttp_parser
DEFS+=-DZT_USE_SYSTEM_HTTP_PARSER
endif
ifeq ($(wildcard /usr/include/json-parser/json.h),)
OBJS+=ext/json-parser/json.o
else
LDLIBS+=-ljsonparser
DEFS+=-DZT_USE_SYSTEM_JSON_PARSER
endif
ifeq ($(ZT_USE_MINIUPNPC),1)
OBJS+=osdep/PortMapper.o

View File

@ -11,7 +11,7 @@ LIBS=
ARCH_FLAGS=-arch x86_64
include objects.mk
OBJS+=osdep/OSXEthernetTap.o ext/lz4/lz4.o ext/json-parser/json.o ext/http-parser/http_parser.o
OBJS+=osdep/OSXEthernetTap.o ext/lz4/lz4.o ext/http-parser/http_parser.o
# Disable codesign since open source users will not have ZeroTier's certs
CODESIGN=echo

View File

@ -181,6 +181,11 @@ public:
break;
case ZT_NETWORK_RULE_ACTION_TEE:
case ZT_NETWORK_RULE_ACTION_REDIRECT:
b.append((uint8_t)14);
b.append((uint64_t)rules[i].v.fwd.address);
b.append((uint32_t)rules[i].v.fwd.flags);
b.append((uint16_t)rules[i].v.fwd.length);
break;
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
b.append((uint8_t)5);
@ -266,6 +271,10 @@ public:
break;
case ZT_NETWORK_RULE_ACTION_TEE:
case ZT_NETWORK_RULE_ACTION_REDIRECT:
rules[ruleCount].v.fwd.address = b.template at<uint64_t>(p);
rules[ruleCount].v.fwd.flags = b.template at<uint32_t>(p + 8);
rules[ruleCount].v.fwd.length = b.template at<uint16_t>(p + 12);
break;
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
rules[ruleCount].v.zt = Address(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt();

View File

@ -154,13 +154,13 @@ static int _doZtFilter(
break;
case ZT_NETWORK_RULE_ACTION_TEE:
case ZT_NETWORK_RULE_ACTION_REDIRECT: {
Packet outp(Address(rules[rn].v.zt),RR->identity.address(),Packet::VERB_EXT_FRAME);
Packet outp(Address(rules[rn].v.fwd.address),RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(nconf.networkId);
outp.append((uint8_t)((rt == ZT_NETWORK_RULE_ACTION_REDIRECT) ? 0x04 : 0x02));
outp.append((uint8_t)( ((rt == ZT_NETWORK_RULE_ACTION_REDIRECT) ? 0x04 : 0x02) | (inbound ? 0x08 : 0x00) ));
macDest.appendTo(outp);
macSource.appendTo(outp);
outp.append((uint16_t)etherType);
outp.append(frameData,frameLen);
outp.append(frameData,(rules[rn].v.fwd.length != 0) ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) ? frameLen : (unsigned int)rules[rn].v.fwd.length) : frameLen);
outp.compress();
RR->sw->send(outp,true);

View File

@ -657,6 +657,7 @@ public:
* 0x01 - Certificate of network membership attached (DEPRECATED)
* 0x02 - Packet is a TEE'd packet
* 0x04 - Packet is a REDIRECT'ed packet
* 0x08 - TEE/REDIRECT'ed packet is on inbound side of connection
*
* An extended frame carries full MAC addressing, making them a
* superset of VERB_FRAME. They're used for bridging or when we

288
one.cpp
View File

@ -48,16 +48,12 @@
#include <string>
#include <stdexcept>
#include <iostream>
#include <sstream>
#include "version.h"
#include "include/ZeroTierOne.h"
#ifdef ZT_USE_SYSTEM_JSON_PARSER
#include <json-parser/json.h>
#else
#include "ext/json-parser/json.h"
#endif
#include "node/Identity.hpp"
#include "node/CertificateOfMembership.hpp"
#include "node/Utils.hpp"
@ -68,6 +64,8 @@
#include "service/OneService.hpp"
#include "ext/json/json.hpp"
#define ZT_PID_PATH "zerotier-one.pid"
using namespace ZeroTier;
@ -283,221 +281,135 @@ static int cli(int argc,char **argv)
return 1;
}
} else if ((command == "info")||(command == "status")) {
unsigned int scode = Http::GET(
1024 * 1024 * 16,
60000,
(const struct sockaddr *)&addr,
"/status",
requestHeaders,
responseHeaders,
responseBody);
const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/status",requestHeaders,responseHeaders,responseBody);
nlohmann::json j;
try {
j = nlohmann::json::parse(responseBody);
} catch (std::exception &exc) {
printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what());
return 1;
} catch ( ... ) {
printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str());
return 1;
}
if (scode == 200) {
std::ostringstream out;
if (json) {
printf("%s",cliFixJsonCRs(responseBody).c_str());
return 0;
out << j.dump(2) << ZT_EOL_S;
} else {
json_value *j = json_parse(responseBody.c_str(),responseBody.length());
bool good = false;
if (j) {
if (j->type == json_object) {
const char *address = (const char *)0;
bool online = false;
const char *version = (const char *)0;
for(unsigned int k=0;k<j->u.object.length;++k) {
if ((!strcmp(j->u.object.values[k].name,"address"))&&(j->u.object.values[k].value->type == json_string))
address = j->u.object.values[k].value->u.string.ptr;
else if ((!strcmp(j->u.object.values[k].name,"version"))&&(j->u.object.values[k].value->type == json_string))
version = j->u.object.values[k].value->u.string.ptr;
else if ((!strcmp(j->u.object.values[k].name,"online"))&&(j->u.object.values[k].value->type == json_boolean))
online = (j->u.object.values[k].value->u.boolean != 0);
}
if ((address)&&(version)) {
printf("200 info %s %s %s" ZT_EOL_S,address,(online ? "ONLINE" : "OFFLINE"),version);
good = true;
}
}
json_value_free(j);
}
if (good) {
return 0;
} else {
printf("%u %s invalid JSON response" ZT_EOL_S,scode,command.c_str());
return 1;
}
if (j.is_object())
out << "200 info " << j["address"].get<std::string>() << " " << j["version"].get<std::string>() << " " << ((j["tcpFallbackActive"]) ? "TUNNELED" : ((j["online"]) ? "ONLINE" : "OFFLINE")) << ZT_EOL_S;
}
printf("%s",out.str().c_str());
return 0;
} else {
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
return 1;
}
} else if (command == "listpeers") {
unsigned int scode = Http::GET(
1024 * 1024 * 16,
60000,
(const struct sockaddr *)&addr,
"/peer",
requestHeaders,
responseHeaders,
responseBody);
const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/peer",requestHeaders,responseHeaders,responseBody);
nlohmann::json j;
try {
j = nlohmann::json::parse(responseBody);
} catch (std::exception &exc) {
printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what());
return 1;
} catch ( ... ) {
printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str());
return 1;
}
if (scode == 200) {
std::ostringstream out;
if (json) {
printf("%s",cliFixJsonCRs(responseBody).c_str());
return 0;
out << j.dump(2) << ZT_EOL_S;
} else {
printf("200 listpeers <ztaddr> <paths> <latency> <version> <role>" ZT_EOL_S);
json_value *j = json_parse(responseBody.c_str(),responseBody.length());
if (j) {
if (j->type == json_array) {
for(unsigned int p=0;p<j->u.array.length;++p) {
json_value *jp = j->u.array.values[p];
if (jp->type == json_object) {
const char *address = (const char *)0;
std::string paths;
int64_t latency = 0;
int64_t versionMajor = -1,versionMinor = -1,versionRev = -1;
const char *role = (const char *)0;
for(unsigned int k=0;k<jp->u.object.length;++k) {
if ((!strcmp(jp->u.object.values[k].name,"address"))&&(jp->u.object.values[k].value->type == json_string))
address = jp->u.object.values[k].value->u.string.ptr;
else if ((!strcmp(jp->u.object.values[k].name,"versionMajor"))&&(jp->u.object.values[k].value->type == json_integer))
versionMajor = jp->u.object.values[k].value->u.integer;
else if ((!strcmp(jp->u.object.values[k].name,"versionMinor"))&&(jp->u.object.values[k].value->type == json_integer))
versionMinor = jp->u.object.values[k].value->u.integer;
else if ((!strcmp(jp->u.object.values[k].name,"versionRev"))&&(jp->u.object.values[k].value->type == json_integer))
versionRev = jp->u.object.values[k].value->u.integer;
else if ((!strcmp(jp->u.object.values[k].name,"role"))&&(jp->u.object.values[k].value->type == json_string))
role = jp->u.object.values[k].value->u.string.ptr;
else if ((!strcmp(jp->u.object.values[k].name,"latency"))&&(jp->u.object.values[k].value->type == json_integer))
latency = jp->u.object.values[k].value->u.integer;
else if ((!strcmp(jp->u.object.values[k].name,"paths"))&&(jp->u.object.values[k].value->type == json_array)) {
for(unsigned int pp=0;pp<jp->u.object.values[k].value->u.array.length;++pp) {
json_value *jpath = jp->u.object.values[k].value->u.array.values[pp];
if (jpath->type == json_object) {
const char *paddr = (const char *)0;
int64_t lastSend = 0;
int64_t lastReceive = 0;
bool preferred = false;
bool active = false;
for(unsigned int kk=0;kk<jpath->u.object.length;++kk) {
if ((!strcmp(jpath->u.object.values[kk].name,"address"))&&(jpath->u.object.values[kk].value->type == json_string))
paddr = jpath->u.object.values[kk].value->u.string.ptr;
else if ((!strcmp(jpath->u.object.values[kk].name,"lastSend"))&&(jpath->u.object.values[kk].value->type == json_integer))
lastSend = jpath->u.object.values[kk].value->u.integer;
else if ((!strcmp(jpath->u.object.values[kk].name,"lastReceive"))&&(jpath->u.object.values[kk].value->type == json_integer))
lastReceive = jpath->u.object.values[kk].value->u.integer;
else if ((!strcmp(jpath->u.object.values[kk].name,"preferred"))&&(jpath->u.object.values[kk].value->type == json_boolean))
preferred = (jpath->u.object.values[kk].value->u.boolean != 0);
else if ((!strcmp(jpath->u.object.values[kk].name,"active"))&&(jpath->u.object.values[kk].value->type == json_boolean))
active = (jpath->u.object.values[kk].value->u.boolean != 0);
}
if ((paddr)&&(active)) {
int64_t now = (int64_t)OSUtils::now();
if (lastSend > 0)
lastSend = now - lastSend;
if (lastReceive > 0)
lastReceive = now - lastReceive;
char pathtmp[256];
Utils::snprintf(pathtmp,sizeof(pathtmp),"%s;%lld;%lld;%s",
paddr,
lastSend,
lastReceive,
(preferred ? "preferred" : "active"));
if (paths.length())
paths.push_back(',');
paths.append(pathtmp);
}
}
}
}
}
if ((address)&&(role)) {
char verstr[64];
if ((versionMajor >= 0)&&(versionMinor >= 0)&&(versionRev >= 0))
Utils::snprintf(verstr,sizeof(verstr),"%lld.%lld.%lld",versionMajor,versionMinor,versionRev);
else {
verstr[0] = '-';
verstr[1] = (char)0;
}
printf("200 listpeers %s %s %lld %s %s" ZT_EOL_S,address,(paths.length()) ? paths.c_str() : "-",(long long)latency,verstr,role);
out << "200 listpeers <ztaddr> <path> <latency> <version> <role>" << ZT_EOL_S;
if (j.is_array()) {
for(unsigned long k=0;k<j.size();++k) {
auto p = j[k];
std::string bestPath;
auto paths = p["paths"];
if (paths.is_array()) {
for(unsigned long i=0;i<paths.size();++i) {
auto path = paths[i];
if (path["preferred"]) {
char tmp[256];
std::string addr = path["address"];
const uint64_t now = OSUtils::now();
Utils::snprintf(tmp,sizeof(tmp),"%s;%llu;%llu",addr.c_str(),now - (uint64_t)path["lastSend"],now - (uint64_t)path["lastReceive"]);
bestPath = tmp;
break;
}
}
}
if (bestPath.length() == 0) bestPath = "-";
char ver[128];
int64_t vmaj = p["versionMajor"];
int64_t vmin = p["versionMinor"];
int64_t vrev = p["versionRev"];
if (vmaj >= 0) {
Utils::snprintf(ver,sizeof(ver),"%lld.%lld.%lld",vmaj,vmin,vrev);
} else {
ver[0] = '-';
ver[1] = (char)0;
}
out << "200 listpeers " << p["address"].get<std::string>() << " " << bestPath << " " << p["latency"] << " " << ver << " " << p["role"].get<std::string>() << ZT_EOL_S;
}
json_value_free(j);
}
return 0;
}
printf("%s",out.str().c_str());
return 0;
} else {
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
return 1;
}
} else if (command == "listnetworks") {
unsigned int scode = Http::GET(
1024 * 1024 * 16,
60000,
(const struct sockaddr *)&addr,
"/network",
requestHeaders,
responseHeaders,
responseBody);
const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/network",requestHeaders,responseHeaders,responseBody);
nlohmann::json j;
try {
j = nlohmann::json::parse(responseBody);
} catch (std::exception &exc) {
printf("%u %s invalid JSON response (%s)" ZT_EOL_S,scode,command.c_str(),exc.what());
return 1;
} catch ( ... ) {
printf("%u %s invalid JSON response (unknown exception)" ZT_EOL_S,scode,command.c_str());
return 1;
}
if (scode == 200) {
std::ostringstream out;
if (json) {
printf("%s",cliFixJsonCRs(responseBody).c_str());
return 0;
out << j.dump(2) << ZT_EOL_S;
} else {
printf("200 listnetworks <nwid> <name> <mac> <status> <type> <dev> <ZT assigned ips>" ZT_EOL_S);
json_value *j = json_parse(responseBody.c_str(),responseBody.length());
if (j) {
if (j->type == json_array) {
for(unsigned int p=0;p<j->u.array.length;++p) {
json_value *jn = j->u.array.values[p];
if (jn->type == json_object) {
const char *nwid = (const char *)0;
const char *name = "";
const char *mac = (const char *)0;
const char *status = (const char *)0;
const char *type = (const char *)0;
const char *portDeviceName = "";
std::string ips;
for(unsigned int k=0;k<jn->u.object.length;++k) {
if ((!strcmp(jn->u.object.values[k].name,"nwid"))&&(jn->u.object.values[k].value->type == json_string))
nwid = jn->u.object.values[k].value->u.string.ptr;
else if ((!strcmp(jn->u.object.values[k].name,"name"))&&(jn->u.object.values[k].value->type == json_string))
name = jn->u.object.values[k].value->u.string.ptr;
else if ((!strcmp(jn->u.object.values[k].name,"mac"))&&(jn->u.object.values[k].value->type == json_string))
mac = jn->u.object.values[k].value->u.string.ptr;
else if ((!strcmp(jn->u.object.values[k].name,"status"))&&(jn->u.object.values[k].value->type == json_string))
status = jn->u.object.values[k].value->u.string.ptr;
else if ((!strcmp(jn->u.object.values[k].name,"type"))&&(jn->u.object.values[k].value->type == json_string))
type = jn->u.object.values[k].value->u.string.ptr;
else if ((!strcmp(jn->u.object.values[k].name,"portDeviceName"))&&(jn->u.object.values[k].value->type == json_string))
portDeviceName = jn->u.object.values[k].value->u.string.ptr;
else if ((!strcmp(jn->u.object.values[k].name,"assignedAddresses"))&&(jn->u.object.values[k].value->type == json_array)) {
for(unsigned int a=0;a<jn->u.object.values[k].value->u.array.length;++a) {
json_value *aa = jn->u.object.values[k].value->u.array.values[a];
if (aa->type == json_string) {
if (ips.length())
ips.push_back(',');
ips.append(aa->u.string.ptr);
}
}
out << "200 listnetworks <nwid> <name> <mac> <status> <type> <dev> <ZT assigned ips>" << ZT_EOL_S;
if (j.is_array()) {
for(unsigned long i=0;i<j.size();++i) {
auto n = j[i];
if (n.is_object()) {
std::string aa;
auto assignedAddresses = n["assignedAddresses"];
if (assignedAddresses.is_array()) {
for(unsigned long j=0;j<assignedAddresses.size();++j) {
auto addr = assignedAddresses[j];
if (addr.is_string()) {
if (aa.length() > 0) aa.push_back(',');
aa.append(addr);
}
}
if ((nwid)&&(mac)&&(status)&&(type)) {
printf("200 listnetworks %s %s %s %s %s %s %s" ZT_EOL_S,
nwid,
(((name)&&(name[0])) ? name : "-"),
mac,
status,
type,
(((portDeviceName)&&(portDeviceName[0])) ? portDeviceName : "-"),
((ips.length() > 0) ? ips.c_str() : "-"));
}
}
if (aa.length() == 0) aa = "-";
out << "200 listnetworks " << n["nwid"].get<std::string>() << " " << n["name"].get<std::string>() << " " << n["mac"].get<std::string>() << " " << n["status"].get<std::string>() << " " << n["type"].get<std::string>() << " " << n["portDeviceName"].get<std::string>() << " " << aa << ZT_EOL_S;
}
}
json_value_free(j);
}
}
printf("%s",out.str().c_str());
return 0;
} else {
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
return 1;

View File

@ -28,11 +28,7 @@
#include "../ext/http-parser/http_parser.h"
#endif
#ifdef ZT_USE_SYSTEM_JSON_PARSER
#include <json-parser/json.h>
#else
#include "../ext/json-parser/json.h"
#endif
#include "../ext/json/json.hpp"
#include "../controller/EmbeddedNetworkController.hpp"
@ -519,23 +515,18 @@ unsigned int ControlPlane::handleRequest(
OneService::NetworkSettings localSettings;
_svc->getNetworkSettings(nws->networks[i].nwid,localSettings);
json_value *j = json_parse(body.c_str(),body.length());
if (j) {
if (j->type == json_object) {
for(unsigned int k=0;k<j->u.object.length;++k) {
if (!strcmp(j->u.object.values[k].name,"allowManaged")) {
if (j->u.object.values[k].value->type == json_boolean)
localSettings.allowManaged = (j->u.object.values[k].value->u.boolean != 0);
} else if (!strcmp(j->u.object.values[k].name,"allowGlobal")) {
if (j->u.object.values[k].value->type == json_boolean)
localSettings.allowGlobal = (j->u.object.values[k].value->u.boolean != 0);
} else if (!strcmp(j->u.object.values[k].name,"allowDefault")) {
if (j->u.object.values[k].value->type == json_boolean)
localSettings.allowDefault = (j->u.object.values[k].value->u.boolean != 0);
}
}
try {
nlohmann::json j(nlohmann::json::parse(body));
if (j.is_object()) {
auto allowManaged = j["allowManaged"];
if (allowManaged.is_boolean()) localSettings.allowManaged = (bool)allowManaged;
auto allowGlobal = j["allowGlobal"];
if (allowGlobal.is_boolean()) localSettings.allowGlobal = (bool)allowGlobal;
auto allowDefault = j["allowDefault"];
if (allowDefault.is_boolean()) localSettings.allowDefault = (bool)allowDefault;
}
json_value_free(j);
} catch ( ... ) {
// discard invalid JSON
}
_svc->setNetworkSettings(nws->networks[i].nwid,localSettings);