summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2016-08-24 13:37:57 -0700
committerAdam Ierymenko <adam.ierymenko@gmail.com>2016-08-24 13:37:57 -0700
commit8e3463d47a8e7565784f349f359ebe7f4a4d0e57 (patch)
tree678b59a6d85bd456649ca4200761386eb64874e5
parent8d594f8b536a1e4acfe62223eb4bd939a8e04fe9 (diff)
downloadinfinitytier-8e3463d47a8e7565784f349f359ebe7f4a4d0e57.tar.gz
infinitytier-8e3463d47a8e7565784f349f359ebe7f4a4d0e57.zip
Add length limit to TEE and REDIRECT, and completely factor out old C json-parser to eliminate a dependency.
-rw-r--r--AUTHORS.md8
-rw-r--r--controller/EmbeddedNetworkController.cpp18
-rw-r--r--ext/json-parser/AUTHORS20
-rw-r--r--ext/json-parser/LICENSE26
-rw-r--r--ext/json-parser/README.md97
-rw-r--r--ext/json-parser/json.c1012
-rw-r--r--ext/json-parser/json.h283
-rw-r--r--include/ZeroTierOne.h14
-rw-r--r--make-freebsd.mk2
-rw-r--r--make-linux.mk6
-rw-r--r--make-mac.mk2
-rw-r--r--node/Capability.hpp9
-rw-r--r--node/Network.cpp6
-rw-r--r--node/Packet.hpp1
-rw-r--r--one.cpp288
-rw-r--r--service/ControlPlane.cpp33
16 files changed, 158 insertions, 1667 deletions
diff --git a/AUTHORS.md b/AUTHORS.md
index aa9e9111..90a64ef6 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -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
diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp
index 4e8d1aad..0a4a17f8 100644
--- a/controller/EmbeddedNetworkController.cpp
+++ b/controller/EmbeddedNetworkController.cpp
@@ -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;
diff --git a/ext/json-parser/AUTHORS b/ext/json-parser/AUTHORS
deleted file mode 100644
index 6a5c799f..00000000
--- a/ext/json-parser/AUTHORS
+++ /dev/null
@@ -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
-
diff --git a/ext/json-parser/LICENSE b/ext/json-parser/LICENSE
deleted file mode 100644
index 1aee375e..00000000
--- a/ext/json-parser/LICENSE
+++ /dev/null
@@ -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.
-
diff --git a/ext/json-parser/README.md b/ext/json-parser/README.md
deleted file mode 100644
index e0b70b6d..00000000
--- a/ext/json-parser/README.md
+++ /dev/null
@@ -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
-
-
diff --git a/ext/json-parser/json.c b/ext/json-parser/json.c
deleted file mode 100644
index 166cdcb6..00000000
--- a/ext/json-parser/json.c
+++ /dev/null
@@ -1,1012 +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.
- */
-
-#include "json.h"
-
-#ifdef _MSC_VER
- #ifndef _CRT_SECURE_NO_WARNINGS
- #define _CRT_SECURE_NO_WARNINGS
- #endif
- #pragma warning(disable:4996)
-#endif
-
-const struct _json_value json_value_none;
-
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <math.h>
-
-typedef unsigned int json_uchar;
-
-static unsigned char hex_value (json_char c)
-{
- if (isdigit(c))
- return c - '0';
-
- switch (c) {
- case 'a': case 'A': return 0x0A;
- case 'b': case 'B': return 0x0B;
- case 'c': case 'C': return 0x0C;
- case 'd': case 'D': return 0x0D;
- case 'e': case 'E': return 0x0E;
- case 'f': case 'F': return 0x0F;
- default: return 0xFF;
- }
-}
-
-typedef struct
-{
- unsigned long used_memory;
-
- unsigned int uint_max;
- unsigned long ulong_max;
-
- json_settings settings;
- int first_pass;
-
- const json_char * ptr;
- unsigned int cur_line, cur_col;
-
-} json_state;
-
-static void * default_alloc (size_t size, int zero, void * user_data)
-{
- return zero ? calloc (1, size) : malloc (size);
-}
-
-static void default_free (void * ptr, void * user_data)
-{
- free (ptr);
-}
-
-static void * json_alloc (json_state * state, unsigned long size, int zero)
-{
- if ((state->ulong_max - state->used_memory) < size)
- return 0;
-
- if (state->settings.max_memory
- && (state->used_memory += size) > state->settings.max_memory)
- {
- return 0;
- }
-
- return state->settings.mem_alloc (size, zero, state->settings.user_data);
-}
-
-static int new_value (json_state * state,
- json_value ** top, json_value ** root, json_value ** alloc,
- json_type type)
-{
- json_value * value;
- int values_size;
-
- if (!state->first_pass)
- {
- value = *top = *alloc;
- *alloc = (*alloc)->_reserved.next_alloc;
-
- if (!*root)
- *root = value;
-
- switch (value->type)
- {
- case json_array:
-
- if (value->u.array.length == 0)
- break;
-
- if (! (value->u.array.values = (json_value **) json_alloc
- (state, value->u.array.length * sizeof (json_value *), 0)) )
- {
- return 0;
- }
-
- value->u.array.length = 0;
- break;
-
- case json_object:
-
- if (value->u.object.length == 0)
- break;
-
- values_size = sizeof (*value->u.object.values) * value->u.object.length;
-
- if (! (value->u.object.values = (json_object_entry *) json_alloc
- (state, values_size + ((unsigned long) value->u.object.values), 0)) )
- {
- return 0;
- }
-
- value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size;
-
- value->u.object.length = 0;
- break;
-
- case json_string:
-
- if (! (value->u.string.ptr = (json_char *) json_alloc
- (state, (value->u.string.length + 1) * sizeof (json_char), 0)) )
- {
- return 0;
- }
-
- value->u.string.length = 0;
- break;
-
- default:
- break;
- };
-
- return 1;
- }
-
- if (! (value = (json_value *) json_alloc
- (state, sizeof (json_value) + state->settings.value_extra, 1)))
- {
- return 0;
- }
-
- if (!*root)
- *root = value;
-
- value->type = type;
- value->parent = *top;
-
- #ifdef JSON_TRACK_SOURCE
- value->line = state->cur_line;
- value->col = state->cur_col;
- #endif
-
- if (*alloc)
- (*alloc)->_reserved.next_alloc = value;
-
- *alloc = *top = value;
-
- return 1;
-}
-
-#define whitespace \
- case '\n': ++ state.cur_line; state.cur_col = 0; \
- case ' ': case '\t': case '\r'
-
-#define string_add(b) \
- do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0);
-
-#define line_and_col \
- state.cur_line, state.cur_col
-
-static const long
- flag_next = 1 << 0,
- flag_reproc = 1 << 1,
- flag_need_comma = 1 << 2,
- flag_seek_value = 1 << 3,
- flag_escaped = 1 << 4,
- flag_string = 1 << 5,
- flag_need_colon = 1 << 6,
- flag_done = 1 << 7,
- flag_num_negative = 1 << 8,
- flag_num_zero = 1 << 9,
- flag_num_e = 1 << 10,
- flag_num_e_got_sign = 1 << 11,
- flag_num_e_negative = 1 << 12,
- flag_line_comment = 1 << 13,
- flag_block_comment = 1 << 14;
-
-json_value * json_parse_ex (json_settings * settings,
- const json_char * json,
- size_t length,
- char * error_buf)
-{
- json_char error [json_error_max];
- const json_char * end;
- json_value * top, * root, * alloc = 0;
- json_state state = { 0 };
- long flags;
- long num_digits = 0, num_e = 0;
- json_int_t num_fraction = 0;
-
- /* Skip UTF-8 BOM
- */
- if (length >= 3 && ((unsigned char) json [0]) == 0xEF
- && ((unsigned char) json [1]) == 0xBB
- && ((unsigned char) json [2]) == 0xBF)
- {
- json += 3;
- length -= 3;
- }
-
- error[0] = '\0';
- end = (json + length);
-
- memcpy (&state.settings, settings, sizeof (json_settings));
-
- if (!state.settings.mem_alloc)
- state.settings.mem_alloc = default_alloc;
-
- if (!state.settings.mem_free)
- state.settings.mem_free = default_free;
-
- memset (&state.uint_max, 0xFF, sizeof (state.uint_max));
- memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max));
-
- state.uint_max -= 8; /* limit of how much can be added before next check */
- state.ulong_max -= 8;
-
- for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass)
- {
- json_uchar uchar;
- unsigned char uc_b1, uc_b2, uc_b3, uc_b4;
- json_char * string = 0;
- unsigned int string_length = 0;
-
- top = root = 0;
- flags = flag_seek_value;
-
- state.cur_line = 1;
-
- for (state.ptr = json ;; ++ state.ptr)
- {
- json_char b = (state.ptr == end ? 0 : *state.ptr);
-
- if (flags & flag_string)
- {
- if (!b)
- { sprintf (error, "Unexpected EOF in string (at %d:%d)", line_and_col);
- goto e_failed;
- }
-
- if (string_length > state.uint_max)
- goto e_overflow;
-
- if (flags & flag_escaped)
- {
- flags &= ~ flag_escaped;
-
- switch (b)
- {
- case 'b': string_add ('\b'); break;
- case 'f': string_add ('\f'); break;
- case 'n': string_add ('\n'); break;
- case 'r': string_add ('\r'); break;
- case 't': string_add ('\t'); break;
- case 'u':
-
- if (end - state.ptr < 4 ||
- (uc_b1 = hex_value (*++ state.ptr)) == 0xFF ||
- (uc_b2 = hex_value (*++ state.ptr)) == 0xFF ||
- (uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
- (uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
- {
- sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col);
- goto e_failed;
- }
-
- uc_b1 = (uc_b1 << 4) | uc_b2;
- uc_b2 = (uc_b3 << 4) | uc_b4;
- uchar = (uc_b1 << 8) | uc_b2;
-
- if ((uchar & 0xF800) == 0xD800) {
- json_uchar uchar2;
-
- if (end - state.ptr < 6 || (*++ state.ptr) != '\\' || (*++ state.ptr) != 'u' ||
- (uc_b1 = hex_value (*++ state.ptr)) == 0xFF ||
- (uc_b2 = hex_value (*++ state.ptr)) == 0xFF ||
- (uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
- (uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
- {
- sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col);
- goto e_failed;
- }
-
- uc_b1 = (uc_b1 << 4) | uc_b2;
- uc_b2 = (uc_b3 << 4) | uc_b4;
- uchar2 = (uc_b1 << 8) | uc_b2;
-
- uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF);
- }
-
- if (sizeof (json_char) >= sizeof (json_uchar) || (uchar <= 0x7F))
- {
- string_add ((json_char) uchar);
- break;
- }
-
- if (uchar <= 0x7FF)
- {
- if (state.first_pass)
- string_length += 2;
- else
- { string [string_length ++] = 0xC0 | (uchar >> 6);
- string [string_length ++] = 0x80 | (uchar & 0x3F);
- }
-
- break;
- }
-
- if (uchar <= 0xFFFF) {
- if (state.first_pass)
- string_length += 3;
- else
- { string [string_length ++] = 0xE0 | (uchar >> 12);
- string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F);
- string [string_length ++] = 0x80 | (uchar & 0x3F);
- }
-
- break;
- }
-
- if (state.first_pass)
- string_length += 4;
- else
- { string [string_length ++] = 0xF0 | (uchar >> 18);
- string [string_length ++] = 0x80 | ((uchar >> 12) & 0x3F);
- string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F);
- string [string_length ++] = 0x80 | (uchar & 0x3F);
- }
-
- break;
-
- default:
- string_add (b);
- };
-
- continue;
- }
-
- if (b == '\\')
- {
- flags |= flag_escaped;
- continue;
- }
-
- if (b == '"')
- {
- if (!state.first_pass)
- string [string_length] = 0;
-
- flags &= ~ flag_string;
- string = 0;
-
- switch (top->type)
- {
- case json_string:
-
- top->u.string.length = string_length;
- flags |= flag_next;
-
- break;
-
- case json_object:
-
- if (state.first_pass)
- (*(json_char **) &top->u.object.values) += string_length + 1;
- else
- {
- top->u.object.values [top->u.object.length].name
- = (json_char *) top->_reserved.object_mem;
-
- top->u.object.values [top->u.object.length].name_length
- = string_length;
-
- (*(json_char **) &top->_reserved.object_mem) += string_length + 1;
- }
-
- flags |= flag_seek_value | flag_need_colon;
- continue;
-
- default:
- break;
- };
- }
- else
- {
- string_add (b);
- continue;
- }
- }
-
- if (state.settings.settings & json_enable_comments)
- {
- if (flags & (flag_line_comment | flag_block_comment))
- {
- if (flags & flag_line_comment)
- {
- if (b == '\r' || b == '\n' || !b)
- {
- flags &= ~ flag_line_comment;
- -- state.ptr; /* so null can be reproc'd */
- }
-
- continue;
- }
-
- if (flags & flag_block_comment)
- {
- if (!b)
- { sprintf (error, "%d:%d: Unexpected EOF in block comment", line_and_col);
- goto e_failed;
- }
-
- if (b == '*' && state.ptr < (end - 1) && state.ptr [1] == '/')
- {
- flags &= ~ flag_block_comment;
- ++ state.ptr; /* skip closing sequence */
- }
-
- continue;
- }
- }
- else if (b == '/')
- {
- if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object)
- { sprintf (error, "%d:%d: Comment not allowed here", line_and_col);
- goto e_failed;
- }
-
- if (++ state.ptr == end)
- { sprintf (error, "%d:%d: EOF unexpected", line_and_col);
- goto e_failed;
- }
-
- switch (b = *state.ptr)
- {
- case '/':
- flags |= flag_line_comment;
- continue;
-
- case '*':
- flags |= flag_block_comment;
- continue;
-
- default:
- sprintf (error, "%d:%d: Unexpected `%c` in comment opening sequence", line_and_col, b);
- goto e_failed;
- };
- }
- }
-
- if (flags & flag_done)
- {
- if (!b)
- break;
-
- switch (b)
- {
- whitespace:
- continue;
-
- default:
-
- sprintf (error, "%d:%d: Trailing garbage: `%c`",
- state.cur_line, state.cur_col, b);
-
- goto e_failed;
- };
- }
-
- if (flags & flag_seek_value)
- {
- switch (b)
- {
- whitespace:
- continue;
-
- case ']':
-
- if (top && top->type == json_array)
- flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next;
- else
- { sprintf (error, "%d:%d: Unexpected ]", line_and_col);
- goto e_failed;
- }
-
- break;
-
- default:
-
- if (flags & flag_need_comma)
- {
- if (b == ',')
- { flags &= ~ flag_need_comma;
- continue;
- }
- else
- {
- sprintf (error, "%d:%d: Expected , before %c",
- state.cur_line, state.cur_col, b);
-
- goto e_failed;
- }
- }
-
- if (flags & flag_need_colon)
- {
- if (b == ':')
- { flags &= ~ flag_need_colon;
- continue;
- }
- else
- {
- sprintf (error, "%d:%d: Expected : before %c",
- state.cur_line, state.cur_col, b);
-
- goto e_failed;
- }
- }
-
- flags &= ~ flag_seek_value;
-
- switch (b)
- {
- case '{':
-
- if (!new_value (&state, &top, &root, &alloc, json_object))
- goto e_alloc_failure;
-
- continue;
-
- case '[':
-
- if (!new_value (&state, &top, &root, &alloc, json_array))
- goto e_alloc_failure;
-
- flags |= flag_seek_value;
- continue;
-
- case '"':
-
- if (!new_value (&state, &top, &root, &alloc, json_string))
- goto e_alloc_failure;
-
- flags |= flag_string;
-
- string = top->u.string.ptr;
- string_length = 0;
-
- continue;
-
- case 't':
-
- if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' ||
- *(++ state.ptr) != 'u' || *(++ state.ptr) != 'e')
- {
- goto e_unknown_value;
- }
-
- if (!new_value (&state, &top, &root, &alloc, json_boolean))
- goto e_alloc_failure;
-
- top->u.boolean = 1;
-
- flags |= flag_next;
- break;
-
- case 'f':
-
- if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' ||
- *(++ state.ptr) != 'l' || *(++ state.ptr) != 's' ||
- *(++ state.ptr) != 'e')
- {
- goto e_unknown_value;
- }
-
- if (!new_value (&state, &top, &root, &alloc, json_boolean))
- goto e_alloc_failure;
-
- flags |= flag_next;
- break;
-
- case 'n':
-
- if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' ||
- *(++ state.ptr) != 'l' || *(++ state.ptr) != 'l')
- {
- goto e_unknown_value;
- }
-
- if (!new_value (&state, &top, &root, &alloc, json_null))
- goto e_alloc_failure;
-
- flags |= flag_next;
- break;
-
- default:
-
- if (isdigit (b) || b == '-')
- {
- if (!new_value (&state, &top, &root, &alloc, json_integer))
- goto e_alloc_failure;
-
- if (!state.first_pass)
- {
- while (isdigit (b) || b == '+' || b == '-'
- || b == 'e' || b == 'E' || b == '.')
- {
- if ( (++ state.ptr) == end)
- {
- b = 0;
- break;
- }
-
- b = *state.ptr;
- }
-
- flags |= flag_next | flag_reproc;
- break;
- }
-
- flags &= ~ (flag_num_negative | flag_num_e |
- flag_num_e_got_sign | flag_num_e_negative |
- flag_num_zero);
-
- num_digits = 0;
- num_fraction = 0;
- num_e = 0;
-
- if (b != '-')
- {
- flags |= flag_reproc;
- break;
- }
-
- flags |= flag_num_negative;
- continue;
- }
- else
- { sprintf (error, "%d:%d: Unexpected %c when seeking value", line_and_col, b);
- goto e_failed;
- }
- };
- };
- }
- else
- {
- switch (top->type)
- {
- case json_object:
-
- switch (b)
- {
- whitespace:
- continue;
-
- case '"':
-
- if (flags & flag_need_comma)
- { sprintf (error, "%d:%d: Expected , before \"", line_and_col);
- goto e_failed;
- }
-
- flags |= flag_string;
-
- string = (json_char *) top->_reserved.object_mem;
- string_length = 0;
-
- break;
-
- case '}':
-
- flags = (flags & ~ flag_need_comma) | flag_next;
- break;
-
- case ',':
-
- if (flags & flag_need_comma)
- {
- flags &= ~ flag_need_comma;
- break;
- }
-
- default:
- sprintf (error, "%d:%d: Unexpected `%c` in object", line_and_col, b);
- goto e_failed;
- };
-
- break;
-
- case json_integer:
- case json_double:
-
- if (isdigit (b))
- {
- ++ num_digits;
-
- if (top->type == json_integer || flags & flag_num_e)
- {
- if (! (flags & flag_num_e))
- {
- if (flags & flag_num_zero)
- { sprintf (error, "%d:%d: Unexpected `0` before `%c`", line_and_col, b);
- goto e_failed;
- }
-
- if (num_digits == 1 && b == '0')
- flags |= flag_num_zero;
- }
- else
- {
- flags |= flag_num_e_got_sign;
- num_e = (num_e * 10) + (b - '0');
- continue;
- }
-
- top->u.integer = (top->u.integer * 10) + (b - '0');
- continue;
- }
-
- num_fraction = (num_fraction * 10) + (b - '0');
- continue;
- }
-
- if (b == '+' || b == '-')
- {
- if ( (flags & flag_num_e) && !(flags & flag_num_e_got_sign))
- {
- flags |= flag_num_e_got_sign;
-
- if (b == '-')
- flags |= flag_num_e_negative;
-
- continue;
- }
- }
- else if (b == '.' && top->type == json_integer)
- {
- if (!num_digits)
- { sprintf (error, "%d:%d: Expected digit before `.`", line_and_col);
- goto e_failed;
- }
-
- top->type = json_double;
- top->u.dbl = (double) top->u.integer;
-
- num_digits = 0;
- continue;
- }
-
- if (! (flags & flag_num_e))
- {
- if (top->type == json_double)
- {
- if (!num_digits)
- { sprintf (error, "%d:%d: Expected digit after `.`", line_and_col);
- goto e_failed;
- }
-
- top->u.dbl += ((double) num_fraction) / (pow (10.0, (double) num_digits));
- }
-
- if (b == 'e' || b == 'E')
- {
- flags |= flag_num_e;
-
- if (top->type == json_integer)
- {
- top->type = json_double;
- top->u.dbl = (double) top->u.integer;
- }
-
- num_digits = 0;
- flags &= ~ flag_num_zero;
-
- continue;
- }
- }
- else
- {
- if (!num_digits)
- { sprintf (error, "%d:%d: Expected digit after `e`", line_and_col);
- goto e_failed;
- }
-
- top->u.dbl *= pow (10.0, (double)
- (flags & flag_num_e_negative ? - num_e : num_e));
- }
-
- if (flags & flag_num_negative)
- {
- if (top->type == json_integer)
- top->u.integer = - top->u.integer;
- else
- top->u.dbl = - top->u.dbl;
- }
-
- flags |= flag_next | flag_reproc;
- break;
-
- default:
- break;
- };
- }
-
- if (flags & flag_reproc)
- {
- flags &= ~ flag_reproc;
- -- state.ptr;
- }
-
- if (flags & flag_next)
- {
- flags = (flags & ~ flag_next) | flag_need_comma;
-
- if (!top->parent)
- {
- /* root value done */
-
- flags |= flag_done;
- continue;
- }
-
- if (top->parent->type == json_array)
- flags |= flag_seek_value;
-
- if (!state.first_pass)
- {
- json_value * parent = top->parent;
-
- switch (parent->type)
- {
- case json_object:
-
- parent->u.object.values
- [parent->u.object.length].value = top;
-
- break;
-
- case json_array:
-
- parent->u.array.values
- [parent->u.array.length] = top;
-
- break;
-
- default:
- break;
- };
- }
-
- if ( (++ top->parent->u.array.length) > state.uint_max)
- goto e_overflow;
-
- top = top->parent;
-
- continue;
- }
- }
-
- alloc = root;
- }
-
- return root;
-
-e_unknown_value:
-
- sprintf (error, "%d:%d: Unknown value", line_and_col);
- goto e_failed;
-
-e_alloc_failure:
-
- strcpy (error, "Memory allocation failure");
- goto e_failed;
-
-e_overflow:
-
- sprintf (error, "%d:%d: Too long (caught overflow)", line_and_col);
- goto e_failed;
-
-e_failed:
-
- if (error_buf)
- {
- if (*error)
- strcpy (error_buf, error);
- else
- strcpy (error_buf, "Unknown error");
- }
-
- if (state.first_pass)
- alloc = root;
-
- while (alloc)
- {
- top = alloc->_reserved.next_alloc;
- state.settings.mem_free (alloc, state.settings.user_data);
- alloc = top;
- }
-
- if (!state.first_pass)
- json_value_free_ex (&state.settings, root);
-
- return 0;
-}
-
-json_value * json_parse (const json_char * json, size_t length)
-{
- json_settings settings = { 0 };
- return json_parse_ex (&settings, json, length, 0);
-}
-
-void json_value_free_ex (json_settings * settings, json_value * value)
-{
- json_value * cur_value;
-
- if (!value)
- return;
-
- value->parent = 0;
-
- while (value)
- {
- switch (value->type)
- {
- case json_array:
-
- if (!value->u.array.length)
- {
- settings->mem_free (value->u.array.values, settings->user_data);
- break;
- }
-
- value = value->u.array.values [-- value->u.array.length];
- continue;
-
- case json_object:
-
- if (!value->u.object.length)
- {
- settings->mem_free (value->u.object.values, settings->user_data);
- break;
- }
-
- value = value->u.object.values [-- value->u.object.length].value;
- continue;
-
- case json_string:
-
- settings->mem_free (value->u.string.ptr, settings->user_data);
- break;
-
- default:
- break;
- };
-
- cur_value = value;
- value = value->parent;
- settings->mem_free (cur_value, settings->user_data);
- }
-}
-
-void json_value_free (json_value * value)
-{
- json_settings settings = { 0 };
- settings.mem_free = default_free;
- json_value_free_ex (&settings, value);
-}
-
diff --git a/ext/json-parser/json.h b/ext/json-parser/json.h
deleted file mode 100644
index f6549ec4..00000000
--- a/ext/json-parser/json.h
+++ /dev/null
@@ -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
-
-
diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h
index aa7ecc2c..5864e346 100644
--- a/include/ZeroTierOne.h
+++ b/include/ZeroTierOne.h
@@ -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;
diff --git a/make-freebsd.mk b/make-freebsd.mk
index e7bd9fd2..cb9a2e6d 100644
--- a/make-freebsd.mk
+++ b/make-freebsd.mk
@@ -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)
diff --git a/make-linux.mk b/make-linux.mk
index fe9ecad8..1fc27bde 100644
--- a/make-linux.mk
+++ b/make-linux.mk
@@ -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
diff --git a/make-mac.mk b/make-mac.mk
index f00f8d6b..ee90ae4c 100644
--- a/make-mac.mk
+++ b/make-mac.mk
@@ -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
diff --git a/node/Capability.hpp b/node/Capability.hpp
index b0620891..0b352725 100644
--- a/node/Capability.hpp
+++ b/node/Capability.hpp
@@ -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();
diff --git a/node/Network.cpp b/node/Network.cpp
index 1319df4e..e12dd027 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -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);
diff --git a/node/Packet.hpp b/node/Packet.hpp
index 0a5d3fec..570bace9 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -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
diff --git a/one.cpp b/one.cpp
index 9f7a0a29..f3442933 100644
--- a/one.cpp
+++ b/one.cpp
@@ -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;
diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp
index 7aa757a9..5ed6b8b7 100644
--- a/service/ControlPlane.cpp
+++ b/service/ControlPlane.cpp
@@ -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);