From fbad36705e9371d1230bdb57157a690538920122 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Mon, 1 Nov 2021 15:59:39 +0000 Subject: [PATCH 01/38] Unify the python API class --- scripts/n2n-httpd | 111 +++++++++------------------------------------- 1 file changed, 20 insertions(+), 91 deletions(-) diff --git a/scripts/n2n-httpd b/scripts/n2n-httpd index 9211915..00af88c 100755 --- a/scripts/n2n-httpd +++ b/scripts/n2n-httpd @@ -23,102 +23,31 @@ import base64 from http import HTTPStatus +import os +import sys +import importlib.machinery +import importlib.util -class JsonUDP(): - """encapsulate communication with the edge""" - def __init__(self, port): - self.address = "127.0.0.1" - self.port = port - self.tag = 0 - self.key = None - self.debug = False - self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self.sock.settimeout(1) +def import_filename(modulename, filename): + # look in the same dir as this script + pathname = os.path.join(os.path.dirname(os.path.abspath(__file__)), + filename) + loader = importlib.machinery.SourceFileLoader(modulename, pathname) + spec = importlib.util.spec_from_loader(modulename, loader) + module = importlib.util.module_from_spec(spec) - def _next_tag(self): - tagstr = str(self.tag) - self.tag = (self.tag + 1) % 1000 - return tagstr + try: + loader.exec_module(module) + except FileNotFoundError as e: + print("Script {} not found".format(pathname), file=sys.stderr) + sys.exit(1) + return module - def _cmdstr(self, msgtype, cmdline): - """Create the full command string to send""" - tagstr = self._next_tag() - options = [tagstr] - if self.key is not None: - options += ['1'] # Flags set for auth key field - options += [self.key] - optionsstr = ':'.join(options) - - return tagstr, ' '.join((msgtype, optionsstr, cmdline)) - - def _rx(self, tagstr): - """Wait for rx packets""" - - # TODO: there are no timeouts with any of the recv calls - data, _ = self.sock.recvfrom(1024) - data = json.loads(data.decode('utf8')) - - # TODO: We assume the first packet we get will be tagged for us - # and be either an "error" or a "begin" - assert(data['_tag'] == tagstr) - - if data['_type'] == 'error': - raise ValueError('Error: {}'.format(data['error'])) - - assert(data['_type'] == 'begin') - - # Ideally, we would confirm that this is our "begin", but that - # would need the cmd passed into this method, and that would - # probably require parsing the cmdline passed to us :-( - # assert(data['cmd'] == cmd) - - result = list() - error = None - - while True: - data, _ = self.sock.recvfrom(1024) - data = json.loads(data.decode('utf8')) - - if data['_tag'] != tagstr: - # this packet is not for us, ignore it - continue - - if data['_type'] == 'error': - # we still expect an end packet, so save the error - error = ValueError('Error: {}'.format(data['error'])) - continue - - if data['_type'] == 'end': - if error: - raise error - return result - - if data['_type'] != 'row': - raise ValueError('Unknown data type {} from ' - 'edge'.format(data['_type'])) - - # remove our boring metadata - del data['_tag'] - del data['_type'] - - if self.debug: - print(data) - - result.append(data) - - def _call(self, msgtype, cmdline): - """Perform a rpc call""" - tagstr, msgstr = self._cmdstr(msgtype, cmdline) - self.sock.sendto(msgstr.encode('utf8'), (self.address, self.port)) - return self._rx(tagstr) - - def read(self, cmdline): - return self._call('r', cmdline) - - def write(self, cmdline): - return self._call('w', cmdline) +# We share the implementation of the RPC class with the n2n-ctl script. We +# cannot just import the module as 'n2n-ctl' has a dash in its name :-( +JsonUDP = import_filename('n2nctl', 'n2n-ctl').JsonUDP pages = { From bcb3c223d953c7c5b38b7a1e408f83bcfe598775 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Mon, 1 Nov 2021 19:22:26 +0000 Subject: [PATCH 02/38] Address lint concern --- scripts/n2n-httpd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/n2n-httpd b/scripts/n2n-httpd index 00af88c..a875047 100755 --- a/scripts/n2n-httpd +++ b/scripts/n2n-httpd @@ -39,7 +39,7 @@ def import_filename(modulename, filename): try: loader.exec_module(module) - except FileNotFoundError as e: + except FileNotFoundError: print("Script {} not found".format(pathname), file=sys.stderr) sys.exit(1) return module From 150c32562da142c0d685c9738996f35affa1b629 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Fri, 5 Nov 2021 12:34:18 +0000 Subject: [PATCH 03/38] Refactor the PHONY make targets to be near their target definitions --- Makefile.in | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index 5f4bd95..3cd4e2e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -146,9 +146,8 @@ SUBDIRS+=tools COVERAGEDIR?=coverage .PHONY: $(SUBDIRS) -.PHONY: steps build push all clean distclean install test cover gcov build-dep -.PHONY: lint lint.python lint.ccode lint.shell lint.yaml +.PHONY: all all: version $(APPS) $(DOCS) $(SUBDIRS) # This allows breaking the build if the version.sh script discovers @@ -188,9 +187,11 @@ $(N2N_LIB): $(N2N_OBJS) win32/n2n_win32.a: win32 +.PHONY: test test: tools scripts/test_harness.sh +.PHONY: lint lint.python lint.ccode lint.shell lint.yaml lint: lint.python lint.ccode lint.shell lint.yaml lint.python: @@ -209,6 +210,7 @@ lint.yaml: # CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="--coverage" # and run the desired tests. Ensure that package gcovr is installed # and then run "make cover" +.PHONY: cover cover: mkdir -p $(COVERAGEDIR) gcovr -s --html --html-details --output=$(COVERAGEDIR)/index.html @@ -217,11 +219,13 @@ cover: # Unfortunately, these end up in the wrong directory due to the # makefile layout # The steps to use this are similar to the "make cover" above +.PHONY: gcov gcov: gcov $(N2N_OBJS) $(MAKE) -C tools gcov # This is a convinent target to use during development or from a CI/CD system +.PHONY: build-dep build-dep: ifeq ($(CONFIG_TARGET),generic) sudo apt install $(BUILD_DEP) @@ -231,11 +235,13 @@ else echo Not attempting to install dependancies for system $(CONFIG_TARGET) endif +.PHONY: clean clean: rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) $(COVERAGEDIR)/ *.dSYM *~ rm -f tests/*.out src/*.gcno src/*.gcda for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean; done +.PHONY: distclean distclean: rm -f tests/*.out src/*.gcno src/*.gcda src/*.indent src/*.unc-backup* rm -rf autom4te.cache/ @@ -246,6 +252,7 @@ distclean: rm -f packages/rpm/config.log packages/rpm/config.status rm -f $(addprefix src/,$(APPS)) +.PHONY: install install: edge supernode edge.8.gz supernode.1.gz n2n.7.gz echo "MANDIR=$(MANDIR)" $(MKDIR) $(SBINDIR) $(MAN1DIR) $(MAN7DIR) $(MAN8DIR) @@ -261,6 +268,7 @@ DOCKER_IMAGE_NAME=ntop/supernode DOCKER_IMAGE_VERSION=$N2N_VERSION_SHORT N2N_COMMIT_HASH=$(shell scripts/version.sh hash) +.PHONY: default steps build push default: steps steps: From 351f7628d013d4d39446ce4d02f0716fb742dfaf Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Fri, 5 Nov 2021 12:36:00 +0000 Subject: [PATCH 04/38] Separate testing out into types, just unit tests for the moment, allowing for integration tests --- Makefile.in | 8 +++++--- scripts/{test_harness.sh => test_units_harness.sh} | 0 2 files changed, 5 insertions(+), 3 deletions(-) rename scripts/{test_harness.sh => test_units_harness.sh} (100%) diff --git a/Makefile.in b/Makefile.in index 3cd4e2e..ae38339 100644 --- a/Makefile.in +++ b/Makefile.in @@ -187,9 +187,11 @@ $(N2N_LIB): $(N2N_OBJS) win32/n2n_win32.a: win32 -.PHONY: test -test: tools - scripts/test_harness.sh +.PHONY: test test.units +test: test.units + +test.units: tools + scripts/test_units_harness.sh .PHONY: lint lint.python lint.ccode lint.shell lint.yaml lint: lint.python lint.ccode lint.shell lint.yaml diff --git a/scripts/test_harness.sh b/scripts/test_units_harness.sh similarity index 100% rename from scripts/test_harness.sh rename to scripts/test_units_harness.sh From 9cc04d6b2858d79f555bd4a09784557b0ba8962b Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Fri, 5 Nov 2021 12:42:51 +0000 Subject: [PATCH 05/38] Limit code coverage to unit tests - any integration tests should not be considered as coverage --- .github/workflows/tests.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 68e5906..5d9165f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -91,8 +91,8 @@ jobs: ./configure shell: bash - - name: Run embedded tests - run: make test + - name: Run embedded unit tests + run: make test.units shell: bash - if: ${{ always() }} @@ -162,8 +162,8 @@ jobs: ./configure shell: bash - - name: Run embedded tests - run: make test + - name: Run embedded unit tests + run: make test.units shell: bash - if: ${{ always() }} @@ -237,8 +237,8 @@ jobs: ./scripts/hack_fakeautoconf.sh shell: bash - - name: Run embedded tests - run: make test + - name: Run embedded unit tests + run: make test.units shell: bash - if: ${{ always() }} From 84f69623e194d90ccf78c53a2a487d7e4ecf70a1 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Fri, 5 Nov 2021 12:45:34 +0000 Subject: [PATCH 06/38] Dont forget to update the other build system --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 634543f..45c3984 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -310,6 +310,6 @@ install(FILES ${PROJECT_BINARY_DIR}/doc/n2n.7.gz # TODO: # - Add the right dependancy so that the tests binaries get built first enable_testing() -add_test(tests ${PROJECT_SOURCE_DIR}/scripts/test_harness.sh ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/tests) +add_test(tests ${PROJECT_SOURCE_DIR}/scripts/test_units_harness.sh ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/tests) endif(DEFINED UNIX) From 954547a9c12e72daea65b2e01b77200f2506aedb Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Fri, 5 Nov 2021 12:56:45 +0000 Subject: [PATCH 07/38] Remove the only obstacle that stopped running the supernode as a normal user --- src/supernode.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/supernode.c b/src/supernode.c index c821614..167d0b3 100644 --- a/src/supernode.c +++ b/src/supernode.c @@ -651,7 +651,6 @@ int main (int argc, char * const argv[]) { if((setgid(sss_node.groupid) != 0) || (setuid(sss_node.userid) != 0)) { traceEvent(TRACE_ERROR, "unable to drop privileges [%u/%s]", errno, strerror(errno)); - exit(1); } } From 3713d357c8257d74d870627e06aece1e0ed580e0 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Fri, 5 Nov 2021 12:57:30 +0000 Subject: [PATCH 08/38] Document the tricky code - TODO, make it less tricky --- src/supernode.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/supernode.c b/src/supernode.c index 167d0b3..8e78a77 100644 --- a/src/supernode.c +++ b/src/supernode.c @@ -639,10 +639,24 @@ int main (int argc, char * const argv[]) { scan->socket_fd = sss_node.sock; #ifndef WIN32 + /* + * If no uid/gid is specified on the commandline, use the uid/gid of the + * first found out of user "n2n" or "nobody" + */ if(((pw = getpwnam ("n2n")) != NULL) || ((pw = getpwnam ("nobody")) != NULL)) { + /* + * If the uid/gid is not set from the CLI, set it from getpwnam + * otherwise reset it to zero + * (TODO: this looks wrong) + */ sss_node.userid = sss_node.userid == 0 ? pw->pw_uid : 0; sss_node.groupid = sss_node.groupid == 0 ? pw->pw_gid : 0; } + + /* + * If we have a non-zero requested uid/gid, attempt to switch to use + * those + */ if((sss_node.userid != 0) || (sss_node.groupid != 0)) { traceEvent(TRACE_NORMAL, "dropping privileges to uid=%d, gid=%d", (signed int)sss_node.userid, (signed int)sss_node.groupid); From e22e453d2c163e17d2db6ae6046367e1b200da15 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Fri, 5 Nov 2021 14:32:07 +0000 Subject: [PATCH 09/38] Add an integration test and a bunch of framework to support tests on multiple build systems --- CMakeLists.txt | 11 +++- Makefile.in | 9 ++- doc/Scripts.md | 30 +++++++-- scripts/test_harness.sh | 50 +++++++++++++++ scripts/test_integration.sh | 11 ++++ scripts/test_integration_supernode.sh | 33 ++++++++++ scripts/test_units.sh | 21 +++++++ scripts/test_units_harness.sh | 40 ------------ tests/test_integration_supernode.sh.expected | 64 ++++++++++++++++++++ 9 files changed, 221 insertions(+), 48 deletions(-) create mode 100755 scripts/test_harness.sh create mode 100755 scripts/test_integration.sh create mode 100755 scripts/test_integration_supernode.sh create mode 100755 scripts/test_units.sh delete mode 100755 scripts/test_units_harness.sh create mode 100644 tests/test_integration_supernode.sh.expected diff --git a/CMakeLists.txt b/CMakeLists.txt index 45c3984..3a486a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -310,6 +310,15 @@ install(FILES ${PROJECT_BINARY_DIR}/doc/n2n.7.gz # TODO: # - Add the right dependancy so that the tests binaries get built first enable_testing() -add_test(tests ${PROJECT_SOURCE_DIR}/scripts/test_units_harness.sh ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/tests) +add_test(NAME unit + COMMAND ${CMAKE_COMMAND} -E env + TOPDIR=${PROJECT_SOURCE_DIR} BINDIR=${PROJECT_BINARY_DIR} + ${PROJECT_SOURCE_DIR}/scripts/test_units.sh +) +add_test(NAME integration + COMMAND ${CMAKE_COMMAND} -E env + TOPDIR=${PROJECT_SOURCE_DIR} BINDIR=${PROJECT_BINARY_DIR} + ${PROJECT_SOURCE_DIR}/scripts/test_integration.sh +) endif(DEFINED UNIX) diff --git a/Makefile.in b/Makefile.in index ae38339..db245b7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -187,11 +187,14 @@ $(N2N_LIB): $(N2N_OBJS) win32/n2n_win32.a: win32 -.PHONY: test test.units -test: test.units +.PHONY: test test.units test.integration +test: test.units test.integration test.units: tools - scripts/test_units_harness.sh + scripts/test_units.sh + +test.integration: $(APPS) + scripts/test_integration.sh .PHONY: lint lint.python lint.ccode lint.shell lint.yaml lint: lint.python lint.ccode lint.shell lint.yaml diff --git a/doc/Scripts.md b/doc/Scripts.md index 297ea24..7146934 100644 --- a/doc/Scripts.md +++ b/doc/Scripts.md @@ -51,10 +51,6 @@ This shell script is a wrapper for the `uncrustify` C code style checker which checks or applies a set of rules to the code. It is used during the automated lint checks. -### `test_harness.sh` - -This shell script is used to run automated tests during development. - ### `n2n-gateway.sh` A sample script to route all the host traffic towards a remote gateway, @@ -96,3 +92,29 @@ Manually test fetching and config: /etc/munin/plugins/n2n_supernode_pkts /etc/munin/plugins/n2n_supernode_pkts config ``` + +## Testing scripts + +### `test_harness.sh` + +This shell script is used to run automated tests during development. It is +run with the name of one or more other scripts, which are then run with their +output being sent to `*.out` files in the `tests` directory and compared with +the matching `*.expected` file in that same dir. + +### `scripts/test_units.sh` + +This runs all the unit tests via the `test_harness.sh`. Unit tests are those +that are testing a small and isolated bit of code. In this project, the unit +tests are the only ones that contribute towards the code coverage report. + +### `scripts/test_integration.sh` + +This runs all the integration tests via the `test_harness.sh`. These are +tests that interact with multiple features and the test is mainly concerned +about the interactions between them (eg, testing an API interface) + +### `scripts/test_integration_supernode.sh` + +This starts a supernode and runs an integration test on the Json API using +the `n2n-ctl` command. diff --git a/scripts/test_harness.sh b/scripts/test_harness.sh new file mode 100755 index 0000000..c6af90c --- /dev/null +++ b/scripts/test_harness.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# +# This expects to find the tests in the tools dir or scripts dir and the +# expected results in the tests dir. +# +# Run with the name(s) of the tests on the commandline + +# boilerplate so we can support whaky cmake dirs +[ -z "$TOPDIR" ] && TOPDIR="." +[ -z "$BINDIR" ] && BINDIR="." +export TOPDIR +export BINDIR + +if [ -d "$BINDIR/tools" ]; then + TOOLSDIR="$BINDIR/tools" +else + TOOLSDIR="$BINDIR" +fi + +TESTS=$* + +SCRIPTSDIR="$TOPDIR/scripts" +TESTDATA="$TOPDIR/tests" + +# Confirm we have all the tools and data +for i in $TESTS; do + if [ ! -e "$TOOLSDIR/$i" ] && [ ! -e "$SCRIPTSDIR/$i" ]; then + echo "Could not find test $i" + exit 1 + fi + if [ ! -e "$TESTDATA/$i.expected" ]; then + echo "Could not find testdata $TESTDATA/$i.expected" + exit 1 + fi +done + +# Actually run the tests +for i in $TESTS; do + if [ -e "$TOOLSDIR/$i" ]; then + TEST="$TOOLSDIR/$i" + elif [ -e "$SCRIPTSDIR/$i" ]; then + TEST="$SCRIPTSDIR/$i" + fi + + echo "$TEST >$TESTDATA/$i.out" + set -e + "$TEST" >"$TESTDATA/$i.out" + cmp "$TESTDATA/$i.expected" "$TESTDATA/$i.out" + set +e +done diff --git a/scripts/test_integration.sh b/scripts/test_integration.sh new file mode 100755 index 0000000..79355ac --- /dev/null +++ b/scripts/test_integration.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# +# Run all the integration tests via the test harness + +# boilerplate so we can support whaky cmake dirs +[ -z "$TOPDIR" ] && TOPDIR=. +[ -z "$BINDIR" ] && BINDIR=. +export TOPDIR +export BINDIR + +${TOPDIR}/scripts/test_harness.sh test_integration_supernode.sh diff --git a/scripts/test_integration_supernode.sh b/scripts/test_integration_supernode.sh new file mode 100755 index 0000000..57f44bc --- /dev/null +++ b/scripts/test_integration_supernode.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# +# Do some quick tests via the Json API against the supernode +# + +AUTH=n2n + +# boilerplate so we can support whaky cmake dirs +[ -z "$TOPDIR" ] && TOPDIR=. +[ -z "$BINDIR" ] && BINDIR=. + +docmd() { + echo "###" + "$@" + echo +} + +# start it running in the background +docmd ${BINDIR}/supernode -v + +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 communities +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 packetstats +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 edges --raw + +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 verbose +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 -k $AUTH --write verbose 1 + +# looks strange, but we are querying the state of the "stop" verb +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 stop + +# stop it +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 -k $AUTH --write stop + diff --git a/scripts/test_units.sh b/scripts/test_units.sh new file mode 100755 index 0000000..b899576 --- /dev/null +++ b/scripts/test_units.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# +# Run all the unit tests via the test harness + +# boilerplate so we can support whaky cmake dirs +[ -z "$TOPDIR" ] && TOPDIR=. +[ -z "$BINDIR" ] && BINDIR=. +export TOPDIR +export BINDIR + +TESTS=" + tests-auth + tests-compress + tests-elliptic + tests-hashing + tests-transform + tests-wire +" + +# shellcheck disable=SC2086 +${TOPDIR}/scripts/test_harness.sh $TESTS diff --git a/scripts/test_units_harness.sh b/scripts/test_units_harness.sh deleted file mode 100755 index 5193297..0000000 --- a/scripts/test_units_harness.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh -# -# This expects to find the tests in the tools dir and the expected results -# in the tests dir. - -TESTS=" - tests-auth - tests-compress - tests-elliptic - tests-hashing - tests-transform - tests-wire -" - -TOOLSDIR=tools -TESTDATA=tests - -# Allow both dirs be overidden -[ -n "$1" ] && TOOLSDIR="$1" -[ -n "$2" ] && TESTDATA="$2" - -# Confirm we have all the tools and data -for i in $TESTS; do - if [ ! -e "$TOOLSDIR/$i" ]; then - echo "Could not find test $TOOLSDIR/$i" - exit 1 - fi - if [ ! -e "$TESTDATA/$i.expected" ]; then - echo "Could not find testdata $TESTDATA/$i.expected" - exit 1 - fi -done - -# Actually run the tests -set -e -for i in $TESTS; do - echo "$TOOLSDIR/$i >$TESTDATA/$i.out" - "$TOOLSDIR/$i" >"$TESTDATA/$i.out" - cmp "$TESTDATA/$i.expected" "$TESTDATA/$i.out" -done diff --git a/tests/test_integration_supernode.sh.expected b/tests/test_integration_supernode.sh.expected new file mode 100644 index 0000000..b1d2a78 --- /dev/null +++ b/tests/test_integration_supernode.sh.expected @@ -0,0 +1,64 @@ +### + +### +[ + { + "community": "-/-", + "ip4addr": "", + "is_federation": 1, + "purgeable": 0 + } +] + +### +[ + { + "tx_pkt": 0, + "type": "forward" + }, + { + "tx_pkt": 0, + "type": "broadcast" + }, + { + "nak": 0, + "rx_pkt": 0, + "type": "reg_super" + }, + { + "tx_pkt": 0, + "type": "errors" + } +] + +### +[] + +### +[ + { + "traceLevel": 3 + } +] + +### +[ + { + "traceLevel": 1 + } +] + +### +[ + { + "keep_running": 1 + } +] + +### +[ + { + "keep_running": 0 + } +] + From e0ce73f684c0981788c7a54fe48692b9178c6922 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 17:40:58 +0000 Subject: [PATCH 10/38] Add management source code as known good for styleguide --- Makefile.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.in b/Makefile.in index db245b7..dc9d0d4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -88,9 +88,11 @@ LINT_CCODE=\ include/n2n_define.h \ include/pearson.h \ include/speck.h \ + src/edge_management.c \ src/edge_utils_win32.c \ src/example_edge_embed_quick_edge_init.c \ src/header_encryption.c \ + src/sn_management.c \ src/sn_selection.c \ src/transform_cc20.c \ src/tuntap_linux.c \ From 6bc08b8e0bc2cf7b727fc9c98e0954730e097983 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 17:42:21 +0000 Subject: [PATCH 11/38] Add more ways to get help from the indent.sh script --- scripts/indent.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/indent.sh b/scripts/indent.sh index 50d38ba..90d977a 100755 --- a/scripts/indent.sh +++ b/scripts/indent.sh @@ -13,6 +13,7 @@ help() { [ -z "$1" ] && help [ "$1" = "-h" ] && help +[ "$1" = "--help" ] && help INPLACE=0 if [ "$1" = "-i" ]; then From 1f501c70ac89684093d28bb2686ff567b619075b Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 17:50:32 +0000 Subject: [PATCH 12/38] Include more known good style-guide files to the linter --- Makefile.in | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Makefile.in b/Makefile.in index dc9d0d4..0018e95 100644 --- a/Makefile.in +++ b/Makefile.in @@ -84,10 +84,18 @@ N2N_DEPS=$(wildcard include/*.h) $(wildcard src/*.c) Makefile # As source files pass the linter, they can be added here (If all the source # is passing the linter tests, this can be refactored) LINT_CCODE=\ + include/curve25519.h \ include/edge_utils_win32.h \ + include/header_encryption.h \ + include/hexdump.h \ include/n2n_define.h \ + include/n2n_wire.h \ + include/network_traffic_filter.h \ include/pearson.h \ + include/random_numbers.h \ + include/sn_selection.h \ include/speck.h \ + include/tf.h \ src/edge_management.c \ src/edge_utils_win32.c \ src/example_edge_embed_quick_edge_init.c \ @@ -95,7 +103,11 @@ LINT_CCODE=\ src/sn_management.c \ src/sn_selection.c \ src/transform_cc20.c \ + src/transform_null.c \ + src/tuntap_freebsd.c \ src/tuntap_linux.c \ + src/tuntap_netbsd.c \ + src/tuntap_osx.c \ src/wire.c \ tools/tests-auth.c \ tools/tests-compress.c \ From ecaba980baf1699d9a92f4587b9215dd6ccb9624 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 19:05:35 +0000 Subject: [PATCH 13/38] Attempt to simplify adding new tests --- CMakeLists.txt | 4 +-- Makefile.in | 4 +-- doc/Scripts.md | 21 ++++++-------- scripts/test_harness.sh | 55 +++++++++++++++++------------------- scripts/test_integration.sh | 11 -------- scripts/test_units.sh | 21 -------------- tests/tests_integration.list | 4 +++ tests/tests_units.list | 9 ++++++ 8 files changed, 52 insertions(+), 77 deletions(-) delete mode 100755 scripts/test_integration.sh delete mode 100755 scripts/test_units.sh create mode 100644 tests/tests_integration.list create mode 100644 tests/tests_units.list diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a486a0..59ac004 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,12 +313,12 @@ enable_testing() add_test(NAME unit COMMAND ${CMAKE_COMMAND} -E env TOPDIR=${PROJECT_SOURCE_DIR} BINDIR=${PROJECT_BINARY_DIR} - ${PROJECT_SOURCE_DIR}/scripts/test_units.sh + ${PROJECT_SOURCE_DIR}/scripts/test_harness.sh ${PROJECT_SOURCE_DIR}/tests/tests_units.list ) add_test(NAME integration COMMAND ${CMAKE_COMMAND} -E env TOPDIR=${PROJECT_SOURCE_DIR} BINDIR=${PROJECT_BINARY_DIR} - ${PROJECT_SOURCE_DIR}/scripts/test_integration.sh + ${PROJECT_SOURCE_DIR}/scripts/test_harness.sh ${PROJECT_SOURCE_DIR}/tests/tests_integration.list ) endif(DEFINED UNIX) diff --git a/Makefile.in b/Makefile.in index 0018e95..1f54f58 100644 --- a/Makefile.in +++ b/Makefile.in @@ -205,10 +205,10 @@ win32/n2n_win32.a: win32 test: test.units test.integration test.units: tools - scripts/test_units.sh + scripts/test_harness.sh tests/tests_units.list test.integration: $(APPS) - scripts/test_integration.sh + scripts/test_harness.sh tests/tests_integration.list .PHONY: lint lint.python lint.ccode lint.shell lint.yaml lint: lint.python lint.ccode lint.shell lint.yaml diff --git a/doc/Scripts.md b/doc/Scripts.md index 7146934..63e5833 100644 --- a/doc/Scripts.md +++ b/doc/Scripts.md @@ -98,21 +98,18 @@ Manually test fetching and config: ### `test_harness.sh` This shell script is used to run automated tests during development. It is -run with the name of one or more other scripts, which are then run with their -output being sent to `*.out` files in the `tests` directory and compared with -the matching `*.expected` file in that same dir. +run with a testlist filename - pointing at a file containing the list of +tests to run. -### `scripts/test_units.sh` +Each test needs a file containing the expected output `${TESTNAME}.expected` +which is expected to exist in the same directory as the testlist (this dir is +referred to as `${listdir}` below). -This runs all the unit tests via the `test_harness.sh`. Unit tests are those -that are testing a small and isolated bit of code. In this project, the unit -tests are the only ones that contribute towards the code coverage report. +Each test is a program, searched for in several locations, including the +`${listdir}/../scripts` dir. -### `scripts/test_integration.sh` - -This runs all the integration tests via the `test_harness.sh`. These are -tests that interact with multiple features and the test is mainly concerned -about the interactions between them (eg, testing an API interface) +Each test is run with its output being sent to `*.out` files in the `listdir` +and compared with the expected output. ### `scripts/test_integration_supernode.sh` diff --git a/scripts/test_harness.sh b/scripts/test_harness.sh index c6af90c..2904305 100755 --- a/scripts/test_harness.sh +++ b/scripts/test_harness.sh @@ -1,9 +1,9 @@ #!/bin/sh # +# Run with the name of a test list file. +# # This expects to find the tests in the tools dir or scripts dir and the # expected results in the tests dir. -# -# Run with the name(s) of the tests on the commandline # boilerplate so we can support whaky cmake dirs [ -z "$TOPDIR" ] && TOPDIR="." @@ -11,40 +11,37 @@ export TOPDIR export BINDIR -if [ -d "$BINDIR/tools" ]; then - TOOLSDIR="$BINDIR/tools" -else - TOOLSDIR="$BINDIR" +if [ -z "$1" ]; then + echo need test list filename + exit 1 fi +TESTLIST="$1" +LISTDIR=$(dirname "$TESTLIST") -TESTS=$* - -SCRIPTSDIR="$TOPDIR/scripts" -TESTDATA="$TOPDIR/tests" - -# Confirm we have all the tools and data -for i in $TESTS; do - if [ ! -e "$TOOLSDIR/$i" ] && [ ! -e "$SCRIPTSDIR/$i" ]; then - echo "Could not find test $i" - exit 1 - fi - if [ ! -e "$TESTDATA/$i.expected" ]; then - echo "Could not find testdata $TESTDATA/$i.expected" - exit 1 - fi -done +TESTS=$(sed -e "s/#.*//" "$TESTLIST") # Actually run the tests for i in $TESTS; do - if [ -e "$TOOLSDIR/$i" ]; then - TEST="$TOOLSDIR/$i" - elif [ -e "$SCRIPTSDIR/$i" ]; then - TEST="$SCRIPTSDIR/$i" + # Look in several places for the test program + if [ -e "$BINDIR/$i" ]; then + TEST="$BINDIR/$i" + elif [ -e "$BINDIR/tools/$i" ]; then + TEST="$BINDIR/tools/$i" + elif [ -e "$LISTDIR/../scripts/$i" ]; then + TEST="$LISTDIR/../scripts/$i" + else + echo "Could not find test $i" + exit 1 fi - echo "$TEST >$TESTDATA/$i.out" + if [ ! -e "$LISTDIR/$i.expected" ]; then + echo "Could not find testdata $LISTDIR/$i.expected" + exit 1 + fi + + echo "$TEST >$LISTDIR/$i.out" set -e - "$TEST" >"$TESTDATA/$i.out" - cmp "$TESTDATA/$i.expected" "$TESTDATA/$i.out" + "$TEST" >"$LISTDIR/$i.out" + cmp "$LISTDIR/$i.expected" "$LISTDIR/$i.out" set +e done diff --git a/scripts/test_integration.sh b/scripts/test_integration.sh deleted file mode 100755 index 79355ac..0000000 --- a/scripts/test_integration.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# -# Run all the integration tests via the test harness - -# boilerplate so we can support whaky cmake dirs -[ -z "$TOPDIR" ] && TOPDIR=. -[ -z "$BINDIR" ] && BINDIR=. -export TOPDIR -export BINDIR - -${TOPDIR}/scripts/test_harness.sh test_integration_supernode.sh diff --git a/scripts/test_units.sh b/scripts/test_units.sh deleted file mode 100755 index b899576..0000000 --- a/scripts/test_units.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -# -# Run all the unit tests via the test harness - -# boilerplate so we can support whaky cmake dirs -[ -z "$TOPDIR" ] && TOPDIR=. -[ -z "$BINDIR" ] && BINDIR=. -export TOPDIR -export BINDIR - -TESTS=" - tests-auth - tests-compress - tests-elliptic - tests-hashing - tests-transform - tests-wire -" - -# shellcheck disable=SC2086 -${TOPDIR}/scripts/test_harness.sh $TESTS diff --git a/tests/tests_integration.list b/tests/tests_integration.list new file mode 100644 index 0000000..d649c4b --- /dev/null +++ b/tests/tests_integration.list @@ -0,0 +1,4 @@ +# +# The integration tests + +test_integration_supernode.sh diff --git a/tests/tests_units.list b/tests/tests_units.list new file mode 100644 index 0000000..6491c1b --- /dev/null +++ b/tests/tests_units.list @@ -0,0 +1,9 @@ +# +# The unit tests + +tests-auth +tests-compress +tests-elliptic +tests-hashing +tests-transform +tests-wire From 004ef6eaafc52257ba1e96a6ce6102801e1d68eb Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 19:13:42 +0000 Subject: [PATCH 14/38] Add quick Json API test for edge --- scripts/test_integration_edge.sh | 47 ++++++++++++++++ tests/test_integration_edge.sh.expected | 71 +++++++++++++++++++++++++ tests/tests_integration.list | 1 + 3 files changed, 119 insertions(+) create mode 100755 scripts/test_integration_edge.sh create mode 100644 tests/test_integration_edge.sh.expected diff --git a/scripts/test_integration_edge.sh b/scripts/test_integration_edge.sh new file mode 100755 index 0000000..349c5b7 --- /dev/null +++ b/scripts/test_integration_edge.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# +# Do some quick tests via the Json API against the edge +# + +AUTH=n2n + +# boilerplate so we can support whaky cmake dirs +[ -z "$TOPDIR" ] && TOPDIR=. +[ -z "$BINDIR" ] && BINDIR=. + +docmd() { + echo "###" + "$@" + echo +} + +# start a supernode +docmd ${BINDIR}/supernode -v + +# Start the edge in the background +docmd sudo ${BINDIR}/edge -l localhost:7654 -c test >/dev/null +# TODO: +# - send edge messages to stderr? + +docmd ${TOPDIR}/scripts/n2n-ctl communities +docmd ${TOPDIR}/scripts/n2n-ctl packetstats +docmd ${TOPDIR}/scripts/n2n-ctl edges --raw + +# TODO: +# docmd ${TOPDIR}/scripts/n2n-ctl supernodes --raw +# - need fixed mac address +# - need to mask out: +# - version string +# - last_seen timestamp +# - uptime + +docmd ${TOPDIR}/scripts/n2n-ctl verbose +docmd ${TOPDIR}/scripts/n2n-ctl -k $AUTH --write verbose 1 + +# looks strange, but we are querying the state of the "stop" verb +docmd ${TOPDIR}/scripts/n2n-ctl stop + +# stop them both +docmd ${TOPDIR}/scripts/n2n-ctl -k $AUTH --write stop +docmd ${TOPDIR}/scripts/n2n-ctl -t 5645 -k $AUTH --write stop + diff --git a/tests/test_integration_edge.sh.expected b/tests/test_integration_edge.sh.expected new file mode 100644 index 0000000..583b2aa --- /dev/null +++ b/tests/test_integration_edge.sh.expected @@ -0,0 +1,71 @@ +### + +### +[ + { + "community": "test" + } +] + +### +[ + { + "rx_pkt": 0, + "tx_pkt": 2, + "type": "transop" + }, + { + "rx_pkt": 0, + "tx_pkt": 0, + "type": "p2p" + }, + { + "rx_pkt": 0, + "tx_pkt": 2, + "type": "super" + }, + { + "rx_pkt": 0, + "tx_pkt": 2, + "type": "super_broadcast" + } +] + +### +[] + +### +[ + { + "traceLevel": 2 + } +] + +### +[ + { + "traceLevel": 1 + } +] + +### +[ + { + "keep_running": 1 + } +] + +### +[ + { + "keep_running": 0 + } +] + +### +[ + { + "keep_running": 0 + } +] + diff --git a/tests/tests_integration.list b/tests/tests_integration.list index d649c4b..ff7ffcc 100644 --- a/tests/tests_integration.list +++ b/tests/tests_integration.list @@ -2,3 +2,4 @@ # The integration tests test_integration_supernode.sh +test_integration_edge.sh From 75a205ec69a6175a0ab76fbd44d7473c608fb511 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 19:19:14 +0000 Subject: [PATCH 15/38] Only need to keep the tests output if there has been a failure --- .github/workflows/tests.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5d9165f..3d2b8a5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -95,14 +95,14 @@ jobs: run: make test.units shell: bash - - if: ${{ always() }} + - if: ${{ failure() }} name: Move test outputs to an arch specific location shell: bash run: | mkdir -p tests/${{ matrix.os }} mv tests/*.out tests/${{ matrix.os }} - - if: ${{ always() }} + - if: ${{ failure() }} name: Upload tests output uses: actions/upload-artifact@v2 with: @@ -166,14 +166,14 @@ jobs: run: make test.units shell: bash - - if: ${{ always() }} + - if: ${{ failure() }} name: Move test outputs to an arch specific location shell: bash run: | mkdir -p tests/${{ matrix.os }} mv tests/*.out tests/${{ matrix.os }} - - if: ${{ always() }} + - if: ${{ failure() }} name: Upload tests output uses: actions/upload-artifact@v2 with: @@ -241,14 +241,14 @@ jobs: run: make test.units shell: bash - - if: ${{ always() }} + - if: ${{ failure() }} name: Move test outputs to an arch specific location shell: bash run: | mkdir -p tests/${{ matrix.os }} mv tests/*.out tests/${{ matrix.os }} - - if: ${{ always() }} + - if: ${{ failure() }} name: Upload tests output uses: actions/upload-artifact@v2 with: From 662e17afd64ad32be25fdf012074fe1b5bc6eaea Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 19:19:42 +0000 Subject: [PATCH 16/38] Keep the tests output on failure for a cmake build too --- .github/workflows/cmake.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index b72c3fd..62059aa 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -66,3 +66,12 @@ jobs: # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more # detail run: ctest -C $BUILD_TYPE + + - if: ${{ failure() }} + name: Upload test data + uses: actions/upload-artifact@v2 + with: + name: tests-out + path: + - tests + - build/Testing From 91d325b73a9a1484d57ebe79ffa5d2b3ec5ef2df Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 19:21:03 +0000 Subject: [PATCH 17/38] actions/upload-artifact@v2 with path does not take a list --- .github/workflows/cmake.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 62059aa..bd04bd9 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -72,6 +72,11 @@ jobs: uses: actions/upload-artifact@v2 with: name: tests-out - path: - - tests - - build/Testing + path: tests + + - if: ${{ failure() }} + name: Upload cmake test output + uses: actions/upload-artifact@v2 + with: + name: tests-out + path: build/Testing From f0d883fde8c5b55b55e75653677f39bcc6d2d6ee Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 19:29:20 +0000 Subject: [PATCH 18/38] of course, tuntap drivers are needed to run edge, so we cannot test that on darwin without writing a dummy tuntap driver --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59ac004..0eea82c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,6 +306,9 @@ install(FILES ${PROJECT_BINARY_DIR}/doc/supernode.1.gz DESTINATION /usr/share/man/man1) install(FILES ${PROJECT_BINARY_DIR}/doc/n2n.7.gz DESTINATION /usr/share/man/man7) +endif(DEFINED UNIX) + +if (CMAKE_SYSTEM_NAME STREQUAL Linux) # TODO: # - Add the right dependancy so that the tests binaries get built first @@ -320,5 +323,4 @@ add_test(NAME integration TOPDIR=${PROJECT_SOURCE_DIR} BINDIR=${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/scripts/test_harness.sh ${PROJECT_SOURCE_DIR}/tests/tests_integration.list ) - -endif(DEFINED UNIX) +endif() From a8e2704b415bb9dc843b470a5fff6e7eefc4b0a5 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 19:46:41 +0000 Subject: [PATCH 19/38] Move all management packet handling for edge into the one source file --- include/n2n.h | 2 +- src/edge_management.c | 233 +++++++++++++++++++++++++++++++++++++++++- src/edge_utils.c | 232 ----------------------------------------- 3 files changed, 233 insertions(+), 234 deletions(-) diff --git a/include/n2n.h b/include/n2n.h index 6ecfb4c..79c4108 100644 --- a/include/n2n.h +++ b/include/n2n.h @@ -285,6 +285,6 @@ int assign_one_ip_subnet (n2n_sn_t *sss, struct sn_community *comm); const char* compression_str (uint8_t cmpr); const char* transop_str (enum n2n_transform tr); -void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock); +void readFromMgmtSocket (n2n_edge_t *eee); void handleMgmtJson_sn (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock); #endif /* _N2N_H_ */ diff --git a/src/edge_management.c b/src/edge_management.c index 5438ae3..bbea528 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -342,7 +342,7 @@ static int mgmt_auth (n2n_edge_t *eee, const struct sockaddr_in sender_sock, enu return 0; } -void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock) { +static void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock) { char cmdlinebuf[80]; enum n2n_mgmt_type type; @@ -455,3 +455,234 @@ void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in se (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); return; } + +/** Read a datagram from the management UDP socket and take appropriate + * action. */ +void readFromMgmtSocket (n2n_edge_t *eee) { + + char udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ + ssize_t recvlen; + /* ssize_t sendlen; */ + struct sockaddr_in sender_sock; + socklen_t i; + size_t msg_len; + time_t now; + struct peer_info *peer, *tmpPeer; + macstr_t mac_buf; + char time_buf[10]; /* 9 digits + 1 terminating zero */ + char uptime_buf[11]; /* 10 digits + 1 terminating zero */ + /* dec_ip_bit_str_t ip_bit_str = {'\0'}; */ + /* dec_ip_str_t ip_str = {'\0'}; */ + in_addr_t net; + n2n_sock_str_t sockbuf; + uint32_t num_pending_peers = 0; + uint32_t num_known_peers = 0; + uint32_t num = 0; + selection_criterion_str_t sel_buf; + + + now = time(NULL); + i = sizeof(sender_sock); + recvlen = recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0 /*flags*/, + (struct sockaddr *) &sender_sock, (socklen_t *) &i); + + if(recvlen < 0) { + traceEvent(TRACE_WARNING, "mgmt recvfrom failed: %d - %s", errno, strerror(errno)); + return; /* failed to receive data from UDP */ + } + + /* avoid parsing any uninitialized junk from the stack */ + udp_buf[recvlen] = 0; + + if((0 == memcmp(udp_buf, "help", 4)) || (0 == memcmp(udp_buf, "?", 1))) { + msg_len = 0; + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "Help for edge management console:\n" + "\tstop | Gracefully exit edge\n" + "\thelp | This help message\n" + "\t+verb | Increase verbosity of logging\n" + "\t-verb | Decrease verbosity of logging\n" + "\tr ... | start query with JSON reply\n" + "\tw ... | start update with JSON reply\n" + "\t | Display statistics\n\n"); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + + return; + } + + if(0 == memcmp(udp_buf, "stop", 4)) { + traceEvent(TRACE_NORMAL, "stop command received"); + *eee->keep_running = 0; + return; + } + + if(0 == memcmp(udp_buf, "+verb", 5)) { + msg_len = 0; + setTraceLevel(getTraceLevel() + 1); + + traceEvent(TRACE_NORMAL, "+verb traceLevel=%u", (unsigned int) getTraceLevel()); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "> +OK traceLevel=%u\n", (unsigned int) getTraceLevel()); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + + return; + } + + if(0 == memcmp(udp_buf, "-verb", 5)) { + msg_len = 0; + + if(getTraceLevel() > 0) { + setTraceLevel(getTraceLevel() - 1); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "> -OK traceLevel=%u\n", getTraceLevel()); + } else { + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "> -NOK traceLevel=%u\n", getTraceLevel()); + } + + traceEvent(TRACE_NORMAL, "-verb traceLevel=%u", (unsigned int) getTraceLevel()); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + return; + } + + if((udp_buf[0] == 'r' || udp_buf[0] == 'w') && (udp_buf[1] == ' ')) { + /* this is a JSON request */ + handleMgmtJson(eee, udp_buf, sender_sock); + return; + } + + traceEvent(TRACE_DEBUG, "mgmt status requested"); + + msg_len = 0; + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "COMMUNITY '%s'\n\n", + (eee->conf.header_encryption == HEADER_ENCRYPTION_NONE) ? (char*)eee->conf.community_name : "-- header encrypted --"); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + " ### | TAP | MAC | EDGE | HINT | LAST SEEN | UPTIME\n"); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "=============================================================================================================\n"); + + // dump nodes with forwarding through supernodes + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "SUPERNODE FORWARD\n"); + num = 0; + HASH_ITER(hh, eee->pending_peers, peer, tmpPeer) { + ++num_pending_peers; + net = htonl(peer->dev_addr.net_addr); + snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->last_seen)); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "%4u | %-15s | %-17s | %-21s | %-15s | %9s |\n", + ++num, + (peer->dev_addr.net_addr == 0) ? "" : inet_ntoa(*(struct in_addr *) &net), + (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + peer->dev_desc, + (peer->last_seen) ? time_buf : ""); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + msg_len = 0; + } + + // dump peer-to-peer nodes + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "-------------------------------------------------------------------------------------------------------------\n"); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "PEER TO PEER\n"); + num = 0; + HASH_ITER(hh, eee->known_peers, peer, tmpPeer) { + ++num_known_peers; + net = htonl(peer->dev_addr.net_addr); + snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->last_seen)); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "%4u | %-15s | %-17s | %-21s | %-15s | %9s |\n", + ++num, + (peer->dev_addr.net_addr == 0) ? "" : inet_ntoa(*(struct in_addr *) &net), + (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + peer->dev_desc, + (peer->last_seen) ? time_buf : ""); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + msg_len = 0; + } + + // dump supernodes + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "-------------------------------------------------------------------------------------------------------------\n"); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "SUPERNODES\n"); + HASH_ITER(hh, eee->conf.supernodes, peer, tmpPeer) { + net = htonl(peer->dev_addr.net_addr); + snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->last_seen)); + snprintf(uptime_buf, sizeof(uptime_buf), "%10u", (unsigned int)(peer->uptime)); + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "%-19s %1s%1s | %-17s | %-21s | %-15s | %9s | %10s\n", + peer->version, + (peer->purgeable == SN_UNPURGEABLE) ? "l" : "", + (peer == eee->curr_sn) ? (eee->sn_wait ? "." : "*" ) : "", + is_null_mac(peer->mac_addr) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + sn_selection_criterion_str(eee, sel_buf, peer), + (peer->last_seen) ? time_buf : "", + (peer->uptime) ? uptime_buf : ""); + + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + msg_len = 0; + } + + // further stats + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "=============================================================================================================\n"); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "uptime %lu | ", + time(NULL) - eee->start_time); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "pend_peers %u | ", + num_pending_peers); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "known_peers %u | ", + num_known_peers); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "transop %u,%u\n", + (unsigned int) eee->transop.tx_cnt, + (unsigned int) eee->transop.rx_cnt); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "super %u,%u | ", + (unsigned int) eee->stats.tx_sup, + (unsigned int) eee->stats.rx_sup); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "p2p %u,%u\n", + (unsigned int) eee->stats.tx_p2p, + (unsigned int) eee->stats.rx_p2p); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "last_super %ld sec ago | ", + (now - eee->last_sup)); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "last_p2p %ld sec ago\n", + (now - eee->last_p2p)); + + msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), + "\nType \"help\" to see more commands.\n\n"); + + /* sendlen = */ sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, + (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); +} diff --git a/src/edge_utils.c b/src/edge_utils.c index b10cf56..056ef64 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -1821,238 +1821,6 @@ static char *get_ip_from_arp (dec_ip_str_t buf, const n2n_mac_t req_mac) { #endif #endif -/** Read a datagram from the management UDP socket and take appropriate - * action. */ -static void readFromMgmtSocket (n2n_edge_t *eee) { - - char udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ - ssize_t recvlen; - /* ssize_t sendlen; */ - struct sockaddr_in sender_sock; - socklen_t i; - size_t msg_len; - time_t now; - struct peer_info *peer, *tmpPeer; - macstr_t mac_buf; - char time_buf[10]; /* 9 digits + 1 terminating zero */ - char uptime_buf[11]; /* 10 digits + 1 terminating zero */ - /* dec_ip_bit_str_t ip_bit_str = {'\0'}; */ - /* dec_ip_str_t ip_str = {'\0'}; */ - in_addr_t net; - n2n_sock_str_t sockbuf; - uint32_t num_pending_peers = 0; - uint32_t num_known_peers = 0; - uint32_t num = 0; - selection_criterion_str_t sel_buf; - - - now = time(NULL); - i = sizeof(sender_sock); - recvlen = recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/, - (struct sockaddr *) &sender_sock, (socklen_t *) &i); - - if(recvlen < 0) { - traceEvent(TRACE_WARNING, "mgmt recvfrom failed: %d - %s", errno, strerror(errno)); - return; /* failed to receive data from UDP */ - } - - /* avoid parsing any uninitialized junk from the stack */ - udp_buf[recvlen] = 0; - - if((0 == memcmp(udp_buf, "help", 4)) || (0 == memcmp(udp_buf, "?", 1))) { - msg_len = 0; - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "Help for edge management console:\n" - "\tstop | Gracefully exit edge\n" - "\thelp | This help message\n" - "\t+verb | Increase verbosity of logging\n" - "\t-verb | Decrease verbosity of logging\n" - "\tr ... | start query with JSON reply\n" - "\tw ... | start update with JSON reply\n" - "\t | Display statistics\n\n"); - - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); - - return; - } - - if(0 == memcmp(udp_buf, "stop", 4)) { - traceEvent(TRACE_NORMAL, "stop command received"); - *eee->keep_running = 0; - return; - } - - if(0 == memcmp(udp_buf, "+verb", 5)) { - msg_len = 0; - setTraceLevel(getTraceLevel() + 1); - - traceEvent(TRACE_NORMAL, "+verb traceLevel=%u", (unsigned int) getTraceLevel()); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "> +OK traceLevel=%u\n", (unsigned int) getTraceLevel()); - - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); - - return; - } - - if(0 == memcmp(udp_buf, "-verb", 5)) { - msg_len = 0; - - if(getTraceLevel() > 0) { - setTraceLevel(getTraceLevel() - 1); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "> -OK traceLevel=%u\n", getTraceLevel()); - } else { - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "> -NOK traceLevel=%u\n", getTraceLevel()); - } - - traceEvent(TRACE_NORMAL, "-verb traceLevel=%u", (unsigned int) getTraceLevel()); - - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); - return; - } - - if((udp_buf[0] == 'r' || udp_buf[0] == 'w') && (udp_buf[1] == ' ')) { - /* this is a JSON request */ - handleMgmtJson(eee, udp_buf, sender_sock); - return; - } - - traceEvent(TRACE_DEBUG, "mgmt status requested"); - - msg_len = 0; - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "COMMUNITY '%s'\n\n", - (eee->conf.header_encryption == HEADER_ENCRYPTION_NONE) ? (char*)eee->conf.community_name : "-- header encrypted --"); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - " ### | TAP | MAC | EDGE | HINT | LAST SEEN | UPTIME\n"); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "=============================================================================================================\n"); - - // dump nodes with forwarding through supernodes - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "SUPERNODE FORWARD\n"); - num = 0; - HASH_ITER(hh, eee->pending_peers, peer, tmpPeer) { - ++num_pending_peers; - net = htonl(peer->dev_addr.net_addr); - snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->last_seen)); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "%4u | %-15s | %-17s | %-21s | %-15s | %9s |\n", - ++num, - (peer->dev_addr.net_addr == 0) ? "" : inet_ntoa(*(struct in_addr *) &net), - (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), - sock_to_cstr(sockbuf, &(peer->sock)), - peer->dev_desc, - (peer->last_seen) ? time_buf : ""); - - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); - msg_len = 0; - } - - // dump peer-to-peer nodes - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "-------------------------------------------------------------------------------------------------------------\n"); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "PEER TO PEER\n"); - num = 0; - HASH_ITER(hh, eee->known_peers, peer, tmpPeer) { - ++num_known_peers; - net = htonl(peer->dev_addr.net_addr); - snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->last_seen)); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "%4u | %-15s | %-17s | %-21s | %-15s | %9s |\n", - ++num, - (peer->dev_addr.net_addr == 0) ? "" : inet_ntoa(*(struct in_addr *) &net), - (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), - sock_to_cstr(sockbuf, &(peer->sock)), - peer->dev_desc, - (peer->last_seen) ? time_buf : ""); - - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); - msg_len = 0; - } - - // dump supernodes - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "-------------------------------------------------------------------------------------------------------------\n"); - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "SUPERNODES\n"); - HASH_ITER(hh, eee->conf.supernodes, peer, tmpPeer) { - net = htonl(peer->dev_addr.net_addr); - snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->last_seen)); - snprintf(uptime_buf, sizeof(uptime_buf), "%10u", (unsigned int)(peer->uptime)); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "%-19s %1s%1s | %-17s | %-21s | %-15s | %9s | %10s\n", - peer->version, - (peer->purgeable == SN_UNPURGEABLE) ? "l" : "", - (peer == eee->curr_sn) ? (eee->sn_wait ? "." : "*" ) : "", - is_null_mac(peer->mac_addr) ? "" : macaddr_str(mac_buf, peer->mac_addr), - sock_to_cstr(sockbuf, &(peer->sock)), - sn_selection_criterion_str(eee, sel_buf, peer), - (peer->last_seen) ? time_buf : "", - (peer->uptime) ? uptime_buf : ""); - - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); - msg_len = 0; - } - - // further stats - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "=============================================================================================================\n"); - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "uptime %lu | ", - time(NULL) - eee->start_time); - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "pend_peers %u | ", - num_pending_peers); - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "known_peers %u | ", - num_known_peers); - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "transop %u,%u\n", - (unsigned int) eee->transop.tx_cnt, - (unsigned int) eee->transop.rx_cnt); - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "super %u,%u | ", - (unsigned int) eee->stats.tx_sup, - (unsigned int) eee->stats.rx_sup); - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "p2p %u,%u\n", - (unsigned int) eee->stats.tx_p2p, - (unsigned int) eee->stats.rx_p2p); - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "last_super %ld sec ago | ", - (now - eee->last_sup)); - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "last_p2p %ld sec ago\n", - (now - eee->last_p2p)); - - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "\nType \"help\" to see more commands.\n\n"); - - /* sendlen = */ sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); -} - - /* ************************************** */ static int check_query_peer_info (n2n_edge_t *eee, time_t now, n2n_mac_t mac) { From ace3dbc44f07c3edeebf5c4aa7eac09cd546f947 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 19:55:31 +0000 Subject: [PATCH 20/38] Move all supernode management handling into one source file --- include/n2n.h | 1 - src/sn_management.c | 163 ++++++++++++++++++++++++++++++++++++++++- src/sn_utils.c | 171 +------------------------------------------- 3 files changed, 163 insertions(+), 172 deletions(-) diff --git a/include/n2n.h b/include/n2n.h index 79c4108..9ca353a 100644 --- a/include/n2n.h +++ b/include/n2n.h @@ -286,5 +286,4 @@ const char* compression_str (uint8_t cmpr); const char* transop_str (enum n2n_transform tr); void readFromMgmtSocket (n2n_edge_t *eee); -void handleMgmtJson_sn (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock); #endif /* _N2N_H_ */ diff --git a/src/sn_management.c b/src/sn_management.c index 0f34a39..b220c00 100644 --- a/src/sn_management.c +++ b/src/sn_management.c @@ -326,7 +326,7 @@ static int mgmt_auth (n2n_sn_t *sss, const struct sockaddr_in sender_sock, enum return 0; } -void handleMgmtJson_sn (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock) { +static void handleMgmtJson (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock) { char cmdlinebuf[80]; enum n2n_mgmt_type type; @@ -439,3 +439,164 @@ void handleMgmtJson_sn (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in s (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); return; } + +static int sendto_mgmt (n2n_sn_t *sss, + const struct sockaddr_in *sender_sock, + const uint8_t *mgmt_buf, + size_t mgmt_size) { + + ssize_t r = sendto(sss->mgmt_sock, (void *)mgmt_buf, mgmt_size, 0 /*flags*/, + (struct sockaddr *)sender_sock, sizeof (struct sockaddr_in)); + + if(r <= 0) { + ++(sss->stats.errors); + traceEvent(TRACE_ERROR, "sendto_mgmt : sendto failed. %s", strerror(errno)); + return -1; + } + + return 0; +} + +int process_mgmt (n2n_sn_t *sss, + const struct sockaddr_in *sender_sock, + char *mgmt_buf, + size_t mgmt_size, + time_t now) { + + char resbuf[N2N_SN_PKTBUF_SIZE]; + size_t ressize = 0; + uint32_t num_edges = 0; + uint32_t num_comm = 0; + uint32_t num = 0; + struct sn_community *community, *tmp; + struct peer_info *peer, *tmpPeer; + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + char time_buf[10]; /* 9 digits + 1 terminating zero */ + dec_ip_bit_str_t ip_bit_str = {'\0'}; + + traceEvent(TRACE_DEBUG, "process_mgmt"); + + /* avoid parsing any uninitialized junk from the stack */ + mgmt_buf[mgmt_size] = 0; + + // process input, if any + if((0 == memcmp(mgmt_buf, "help", 4)) || (0 == memcmp(mgmt_buf, "?", 1))) { + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "Help for supernode management console:\n" + "\thelp | This help message\n" + "\treload_communities | Reloads communities and user's public keys\n" + "\t | Display status and statistics\n"); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + return 0; /* no status output afterwards */ + } + + if(0 == memcmp(mgmt_buf, "reload_communities", 18)) { + if(!sss->community_file) { + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "No community file provided (-c command line option)\n"); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + return 0; /* no status output afterwards */ + } + traceEvent(TRACE_NORMAL, "'reload_communities' command"); + + if(load_allowed_sn_community(sss)) { + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "Error while re-loading community file (not found or no valid content)\n"); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + return 0; /* no status output afterwards */ + } + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "OK.\n"); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + return 0; /* no status output afterwards */ + } + + if((mgmt_buf[0] == 'r' || mgmt_buf[0] == 'w') && (mgmt_buf[1] == ' ')) { + /* this is a JSON request */ + handleMgmtJson(sss, mgmt_buf, *sender_sock); + return 0; + } + + // output current status + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + " ### | TAP | MAC | EDGE | HINT | LAST SEEN\n"); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "========================================================================================================\n"); + HASH_ITER(hh, sss->communities, community, tmp) { + if(num_comm) + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "--------------------------------------------------------------------------------------------------------\n"); + num_comm++; + num_edges += HASH_COUNT(community->edges); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "%s '%s'\n", + (community->is_federation) ? "FEDERATION" : ((community->purgeable == COMMUNITY_UNPURGEABLE) ? "FIXED NAME COMMUNITY" : "COMMUNITY"), + (community->is_federation) ? "-/-" : community->community); + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + ressize = 0; + + num = 0; + HASH_ITER(hh, community->edges, peer, tmpPeer) { + sprintf(time_buf, "%9u", (unsigned int)(now - peer->last_seen)); + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "%4u | %-19s | %-17s | %-21s %-3s | %-15s | %9s\n", + ++num, + (peer->dev_addr.net_addr == 0) ? ((peer->purgeable == SN_UNPURGEABLE) ? "-l" : "") : ip_subnet_to_str(ip_bit_str, &peer->dev_addr), + (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock)), + ((peer->socket_fd >= 0) && (peer->socket_fd != sss->sock)) ? "TCP" : "", + peer->dev_desc, + (peer->last_seen) ? time_buf : ""); + + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + ressize = 0; + } + } + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "========================================================================================================\n"); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "uptime %lu | ", (now - sss->start_time)); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "edges %u | ", + num_edges); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "reg_sup %u | ", + (unsigned int) sss->stats.reg_super); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "reg_nak %u | ", + (unsigned int) sss->stats.reg_super_nak); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "errors %u \n", + (unsigned int) sss->stats.errors); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "fwd %u | ", + (unsigned int) sss->stats.fwd); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "broadcast %u | ", + (unsigned int) sss->stats.broadcast); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "cur_cmnts %u\n", HASH_COUNT(sss->communities)); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "last_fwd %lu sec ago | ", + (long unsigned int) (now - sss->stats.last_fwd)); + + ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, + "last reg %lu sec ago\n\n", + (long unsigned int) (now - sss->stats.last_reg_super)); + + sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); + + return 0; +} diff --git a/src/sn_utils.c b/src/sn_utils.c index 464eb9e..b14469d 100644 --- a/src/sn_utils.c +++ b/src/sn_utils.c @@ -30,11 +30,6 @@ static ssize_t sendto_peer (n2n_sn_t *sss, const uint8_t *pktbuf, size_t pktsize); -static int sendto_mgmt (n2n_sn_t *sss, - const struct sockaddr_in *sender_sock, - const uint8_t *mgmt_buf, - size_t mgmt_size); - static uint16_t reg_lifetime (n2n_sn_t *sss); static int update_edge (n2n_sn_t *sss, @@ -61,7 +56,7 @@ static int sort_communities (n2n_sn_t *sss, time_t* p_last_sort, time_t now); -static int process_mgmt (n2n_sn_t *sss, +int process_mgmt (n2n_sn_t *sss, const struct sockaddr_in *sender_sock, char *mgmt_buf, size_t mgmt_size, @@ -1501,170 +1496,6 @@ static int sort_communities (n2n_sn_t *sss, } -static int process_mgmt (n2n_sn_t *sss, - const struct sockaddr_in *sender_sock, - char *mgmt_buf, - size_t mgmt_size, - time_t now) { - - char resbuf[N2N_SN_PKTBUF_SIZE]; - size_t ressize = 0; - uint32_t num_edges = 0; - uint32_t num_comm = 0; - uint32_t num = 0; - struct sn_community *community, *tmp; - struct peer_info *peer, *tmpPeer; - macstr_t mac_buf; - n2n_sock_str_t sockbuf; - char time_buf[10]; /* 9 digits + 1 terminating zero */ - dec_ip_bit_str_t ip_bit_str = {'\0'}; - - traceEvent(TRACE_DEBUG, "process_mgmt"); - - /* avoid parsing any uninitialized junk from the stack */ - mgmt_buf[mgmt_size] = 0; - - // process input, if any - if((0 == memcmp(mgmt_buf, "help", 4)) || (0 == memcmp(mgmt_buf, "?", 1))) { - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "Help for supernode management console:\n" - "\thelp | This help message\n" - "\treload_communities | Reloads communities and user's public keys\n" - "\t | Display status and statistics\n"); - sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); - return 0; /* no status output afterwards */ - } - - if(0 == memcmp(mgmt_buf, "reload_communities", 18)) { - if(!sss->community_file) { - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "No community file provided (-c command line option)\n"); - sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); - return 0; /* no status output afterwards */ - } - traceEvent(TRACE_NORMAL, "'reload_communities' command"); - - if(load_allowed_sn_community(sss)) { - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "Error while re-loading community file (not found or no valid content)\n"); - sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); - return 0; /* no status output afterwards */ - } - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "OK.\n"); - sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); - return 0; /* no status output afterwards */ - } - - if((mgmt_buf[0] == 'r' || mgmt_buf[0] == 'w') && (mgmt_buf[1] == ' ')) { - /* this is a JSON request */ - handleMgmtJson_sn(sss, mgmt_buf, *sender_sock); - return 0; - } - - // output current status - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - " ### | TAP | MAC | EDGE | HINT | LAST SEEN\n"); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "========================================================================================================\n"); - HASH_ITER(hh, sss->communities, community, tmp) { - if(num_comm) - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "--------------------------------------------------------------------------------------------------------\n"); - num_comm++; - num_edges += HASH_COUNT(community->edges); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "%s '%s'\n", - (community->is_federation) ? "FEDERATION" : - ((community->purgeable == COMMUNITY_UNPURGEABLE) ? "FIXED NAME COMMUNITY" : "COMMUNITY"), - (community->is_federation) ? "-/-" : community->community); - sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); - ressize = 0; - - num = 0; - HASH_ITER(hh, community->edges, peer, tmpPeer) { - sprintf (time_buf, "%9u", (unsigned int)(now - peer->last_seen)); - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "%4u | %-19s | %-17s | %-21s %-3s | %-15s | %9s\n", - ++num, - (peer->dev_addr.net_addr == 0) ? ((peer->purgeable == SN_UNPURGEABLE) ? "-l" : "") : - ip_subnet_to_str(ip_bit_str, &peer->dev_addr), - (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), - sock_to_cstr(sockbuf, &(peer->sock)), - ((peer->socket_fd >= 0) && (peer->socket_fd != sss->sock)) ? "TCP" : "", - peer->dev_desc, - (peer->last_seen) ? time_buf : ""); - - sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); - ressize = 0; - } - } - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "========================================================================================================\n"); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "uptime %lu | ", (now - sss->start_time)); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "edges %u | ", - num_edges); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "reg_sup %u | ", - (unsigned int) sss->stats.reg_super); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "reg_nak %u | ", - (unsigned int) sss->stats.reg_super_nak); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "errors %u \n", - (unsigned int) sss->stats.errors); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "fwd %u | ", - (unsigned int) sss->stats.fwd); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "broadcast %u | ", - (unsigned int) sss->stats.broadcast); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "cur_cmnts %u\n", HASH_COUNT(sss->communities)); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "last_fwd %lu sec ago | ", - (long unsigned int) (now - sss->stats.last_fwd)); - - ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize, - "last reg %lu sec ago\n\n", - (long unsigned int) (now - sss->stats.last_reg_super)); - - sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize); - - return 0; -} - - -static int sendto_mgmt (n2n_sn_t *sss, - const struct sockaddr_in *sender_sock, - const uint8_t *mgmt_buf, - size_t mgmt_size) { - - ssize_t r = sendto(sss->mgmt_sock, (void *)mgmt_buf, mgmt_size, 0 /*flags*/, - (struct sockaddr *)sender_sock, sizeof (struct sockaddr_in)); - - if(r <= 0) { - ++(sss->stats.errors); - traceEvent (TRACE_ERROR, "sendto_mgmt : sendto failed. %s", strerror (errno)); - return -1; - } - - return 0; -} - /** Examine a datagram and determine what to do with it. * */ From 6e4cf85915d571bc1ed63645e53c7e6f5a11eda9 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 20:16:06 +0000 Subject: [PATCH 21/38] As we are in our own namespace, we can ditch the n2n_ prefix to some definitions --- src/edge_management.c | 10 +++++----- src/sn_management.c | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/edge_management.c b/src/edge_management.c index bbea528..bb2184a 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -20,12 +20,12 @@ #include "edge_utils_win32.h" #define FLAG_WROK 1 -typedef struct n2n_mgmt_handler { +typedef struct mgmt_handler { int flags; char *cmd; char *help; void (*func)(n2n_edge_t *eee, char *udp_buf, struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv); -} n2n_mgmt_handler_t; +} mgmt_handler_t; static void mgmt_error (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, char *tag, char *msg) { size_t msg_len; @@ -279,7 +279,7 @@ static void mgmt_unimplemented (n2n_edge_t *eee, char *udp_buf, const struct soc static void mgmt_help (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv); -n2n_mgmt_handler_t mgmt_handlers[] = { +mgmt_handler_t mgmt_handlers[] = { { .cmd = "reload_communities", .flags = FLAG_WROK, .help = "Reserved for supernode", .func = mgmt_unimplemented}, { .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop}, @@ -295,7 +295,7 @@ n2n_mgmt_handler_t mgmt_handlers[] = { static void mgmt_help (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { size_t msg_len; - n2n_mgmt_handler_t *handler; + mgmt_handler_t *handler; /* * Even though this command is readonly, we deliberately do not check @@ -354,7 +354,7 @@ static void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockadd char *flagstr; int flags; char *auth; - n2n_mgmt_handler_t *handler; + mgmt_handler_t *handler; size_t msg_len; /* save a copy of the commandline before we reuse the udp_buf */ diff --git a/src/sn_management.c b/src/sn_management.c index b220c00..e4aa7aa 100644 --- a/src/sn_management.c +++ b/src/sn_management.c @@ -27,12 +27,12 @@ int load_allowed_sn_community (n2n_sn_t *sss); /* defined in sn_utils.c */ #define FLAG_WROK 1 -typedef struct n2n_mgmt_handler { +typedef struct mgmt_handler { int flags; char *cmd; char *help; void (*func)(n2n_sn_t *sss, char *udp_buf, struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv); -} n2n_mgmt_handler_t; +} mgmt_handler_t; static void mgmt_error (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, char *tag, char *msg) { size_t msg_len; @@ -263,7 +263,7 @@ static void mgmt_unimplemented (n2n_sn_t *sss, char *udp_buf, const struct socka static void mgmt_help (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv); -n2n_mgmt_handler_t mgmt_handlers[] = { +mgmt_handler_t mgmt_handlers[] = { { .cmd = "supernodes", .help = "Reserved for edge", .func = mgmt_unimplemented}, { .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop}, @@ -279,7 +279,7 @@ n2n_mgmt_handler_t mgmt_handlers[] = { static void mgmt_help (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { size_t msg_len; - n2n_mgmt_handler_t *handler; + mgmt_handler_t *handler; /* * Even though this command is readonly, we deliberately do not check @@ -338,7 +338,7 @@ static void handleMgmtJson (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_ char *flagstr; int flags; char *auth; - n2n_mgmt_handler_t *handler; + mgmt_handler_t *handler; size_t msg_len; /* save a copy of the commandline before we reuse the udp_buf */ From 9278e158965194c11a6be820442e81dfe934bbe2 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 20:41:33 +0000 Subject: [PATCH 22/38] Add at least one test that should cause a failed auth --- scripts/test_integration_edge.sh | 1 + tests/test_integration_edge.sh.expected | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/scripts/test_integration_edge.sh b/scripts/test_integration_edge.sh index 349c5b7..50ae6dd 100755 --- a/scripts/test_integration_edge.sh +++ b/scripts/test_integration_edge.sh @@ -36,6 +36,7 @@ docmd ${TOPDIR}/scripts/n2n-ctl edges --raw # - uptime docmd ${TOPDIR}/scripts/n2n-ctl verbose +docmd ${TOPDIR}/scripts/n2n-ctl --write verbose 1 2>&1 docmd ${TOPDIR}/scripts/n2n-ctl -k $AUTH --write verbose 1 # looks strange, but we are querying the state of the "stop" verb diff --git a/tests/test_integration_edge.sh.expected b/tests/test_integration_edge.sh.expected index 583b2aa..8e13193 100644 --- a/tests/test_integration_edge.sh.expected +++ b/tests/test_integration_edge.sh.expected @@ -41,6 +41,22 @@ } ] +### +Traceback (most recent call last): + File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 258, in + main() + File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 249, in main + result = func(rpc, args) + File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 205, in subcmd_default + rows = rpc.write(cmdline) + File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 106, in write + return self._call('w', cmdline) + File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 100, in _call + return self._rx(tagstr) + File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 53, in _rx + raise ValueError('Error: {}'.format(data['error'])) +ValueError: Error: badauth + ### [ { From 35c83a08254333ea291706cd8757d46545fd3894 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 20:56:19 +0000 Subject: [PATCH 23/38] Simplify edge mgmt handling by building a request structure and using it for replies --- src/edge_management.c | 231 +++++++++++++++++++++--------------------- 1 file changed, 113 insertions(+), 118 deletions(-) diff --git a/src/edge_management.c b/src/edge_management.c index bb2184a..be8a8c4 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -19,32 +19,47 @@ #include "n2n.h" #include "edge_utils_win32.h" +/* + * Everything needed to reply to a request + */ +typedef struct mgmt_req { + n2n_edge_t *eee; + enum n2n_mgmt_type type; + char *tag; + struct sockaddr_in sender_sock; +} mgmt_req_t; + #define FLAG_WROK 1 typedef struct mgmt_handler { int flags; char *cmd; char *help; - void (*func)(n2n_edge_t *eee, char *udp_buf, struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv); + void (*func)(mgmt_req_t *reg, char *udp_buf, char *argv0, char *argv); } mgmt_handler_t; -static void mgmt_error (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, char *tag, char *msg) { +static void send_reply (mgmt_req_t *req, char *udp_buf, size_t msg_len) { + // TODO: error handling + sendto(req->eee->udp_mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &req->sender_sock, sizeof(struct sockaddr_in)); +} + +static void mgmt_error (mgmt_req_t *req, char *udp_buf, char *msg) { size_t msg_len; msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, "{" "\"_tag\":\"%s\"," "\"_type\":\"error\"," "\"error\":\"%s\"}\n", - tag, + req->tag, msg); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); } -static void mgmt_stop (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { +static void mgmt_stop (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { size_t msg_len; - if(type==N2N_MGMT_WRITE) { - *eee->keep_running = 0; + if(req->type==N2N_MGMT_WRITE) { + *req->eee->keep_running = 0; } msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, @@ -52,17 +67,16 @@ static void mgmt_stop (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in "\"_tag\":\"%s\"," "\"_type\":\"row\"," "\"keep_running\":%u}\n", - tag, - *eee->keep_running); + req->tag, + *req->eee->keep_running); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); } -static void mgmt_verbose (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { +static void mgmt_verbose (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { size_t msg_len; - if(type==N2N_MGMT_WRITE) { + if(req->type==N2N_MGMT_WRITE) { if(argv) { setTraceLevel(strtoul(argv, NULL, 0)); } @@ -73,18 +87,17 @@ static void mgmt_verbose (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_ "\"_tag\":\"%s\"," "\"_type\":\"row\"," "\"traceLevel\":%u}\n", - tag, + req->tag, getTraceLevel()); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); } -static void mgmt_communities (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { +static void mgmt_communities (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { size_t msg_len; - if(eee->conf.header_encryption != HEADER_ENCRYPTION_NONE) { - mgmt_error(eee, udp_buf, sender_sock, tag, "noaccess"); + if(req->eee->conf.header_encryption != HEADER_ENCRYPTION_NONE) { + mgmt_error(req, udp_buf, "noaccess"); return; } @@ -93,21 +106,20 @@ static void mgmt_communities (n2n_edge_t *eee, char *udp_buf, const struct socka "\"_tag\":\"%s\"," "\"_type\":\"row\"," "\"community\":\"%s\"}", - tag, - eee->conf.community_name); + req->tag, + req->eee->conf.community_name); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); } -static void mgmt_supernodes (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { +static void mgmt_supernodes (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { size_t msg_len; struct peer_info *peer, *tmpPeer; macstr_t mac_buf; n2n_sock_str_t sockbuf; selection_criterion_str_t sel_buf; - HASH_ITER(hh, eee->conf.supernodes, peer, tmpPeer) { + HASH_ITER(hh, req->eee->conf.supernodes, peer, tmpPeer) { /* * TODO: @@ -128,22 +140,21 @@ static void mgmt_supernodes (n2n_edge_t *eee, char *udp_buf, const struct sockad "\"selection\":\"%s\"," "\"last_seen\":%li," "\"uptime\":%li}\n", - tag, + req->tag, peer->version, peer->purgeable, - (peer == eee->curr_sn) ? (eee->sn_wait ? 2 : 1 ) : 0, + (peer == req->eee->curr_sn) ? (req->eee->sn_wait ? 2 : 1 ) : 0, is_null_mac(peer->mac_addr) ? "" : macaddr_str(mac_buf, peer->mac_addr), sock_to_cstr(sockbuf, &(peer->sock)), - sn_selection_criterion_str(eee, sel_buf, peer), + sn_selection_criterion_str(req->eee, sel_buf, peer), peer->last_seen, peer->uptime); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); } } -static void mgmt_edges_row (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, char *tag, struct peer_info *peer, char *mode) { +static void mgmt_edges_row (mgmt_req_t *req, char *udp_buf, struct peer_info *peer, char *mode) { size_t msg_len; macstr_t mac_buf; n2n_sock_str_t sockbuf; @@ -163,7 +174,7 @@ static void mgmt_edges_row (n2n_edge_t *eee, char *udp_buf, const struct sockadd "\"last_p2p\":%li,\n" "\"last_sent_query\":%li,\n" "\"last_seen\":%li}\n", - tag, + req->tag, mode, (peer->dev_addr.net_addr == 0) ? "" : ip_subnet_to_str(ip_bit_str, &peer->dev_addr), peer->purgeable, @@ -175,25 +186,24 @@ static void mgmt_edges_row (n2n_edge_t *eee, char *udp_buf, const struct sockadd peer->last_sent_query, peer->last_seen); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); } -static void mgmt_edges (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { +static void mgmt_edges (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { struct peer_info *peer, *tmpPeer; // dump nodes with forwarding through supernodes - HASH_ITER(hh, eee->pending_peers, peer, tmpPeer) { - mgmt_edges_row(eee, udp_buf, sender_sock, tag, peer, "pSp"); + HASH_ITER(hh, req->eee->pending_peers, peer, tmpPeer) { + mgmt_edges_row(req, udp_buf, peer, "pSp"); } // dump peer-to-peer nodes - HASH_ITER(hh, eee->known_peers, peer, tmpPeer) { - mgmt_edges_row(eee, udp_buf, sender_sock, tag, peer, "p2p"); + HASH_ITER(hh, req->eee->known_peers, peer, tmpPeer) { + mgmt_edges_row(req, udp_buf, peer, "p2p"); } } -static void mgmt_timestamps (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { +static void mgmt_timestamps (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { size_t msg_len; msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, @@ -203,16 +213,15 @@ static void mgmt_timestamps (n2n_edge_t *eee, char *udp_buf, const struct sockad "\"start_time\":%lu," "\"last_super\":%ld," "\"last_p2p\":%ld}\n", - tag, - eee->start_time, - eee->last_sup, - eee->last_p2p); + req->tag, + req->eee->start_time, + req->eee->last_sup, + req->eee->last_p2p); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); } -static void mgmt_packetstats (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { +static void mgmt_packetstats (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { size_t msg_len; msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, @@ -222,12 +231,11 @@ static void mgmt_packetstats (n2n_edge_t *eee, char *udp_buf, const struct socka "\"type\":\"transop\"," "\"tx_pkt\":%lu," "\"rx_pkt\":%lu}\n", - tag, - eee->transop.tx_cnt, - eee->transop.rx_cnt); + req->tag, + req->eee->transop.tx_cnt, + req->eee->transop.rx_cnt); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, "{" @@ -236,12 +244,11 @@ static void mgmt_packetstats (n2n_edge_t *eee, char *udp_buf, const struct socka "\"type\":\"p2p\"," "\"tx_pkt\":%u," "\"rx_pkt\":%u}\n", - tag, - eee->stats.tx_p2p, - eee->stats.rx_p2p); + req->tag, + req->eee->stats.tx_p2p, + req->eee->stats.rx_p2p); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, "{" @@ -250,12 +257,11 @@ static void mgmt_packetstats (n2n_edge_t *eee, char *udp_buf, const struct socka "\"type\":\"super\"," "\"tx_pkt\":%u," "\"rx_pkt\":%u}\n", - tag, - eee->stats.tx_sup, - eee->stats.rx_sup); + req->tag, + req->eee->stats.tx_sup, + req->eee->stats.rx_sup); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, "{" @@ -264,20 +270,19 @@ static void mgmt_packetstats (n2n_edge_t *eee, char *udp_buf, const struct socka "\"type\":\"super_broadcast\"," "\"tx_pkt\":%u," "\"rx_pkt\":%u}\n", - tag, - eee->stats.tx_sup_broadcast, - eee->stats.rx_sup_broadcast); + req->tag, + req->eee->stats.tx_sup_broadcast, + req->eee->stats.rx_sup_broadcast); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); } -static void mgmt_unimplemented (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { +static void mgmt_unimplemented (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { - mgmt_error(eee, udp_buf, sender_sock, tag, "unimplemented"); + mgmt_error(req, udp_buf, "unimplemented"); } -static void mgmt_help (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv); +static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv); mgmt_handler_t mgmt_handlers[] = { { .cmd = "reload_communities", .flags = FLAG_WROK, .help = "Reserved for supernode", .func = mgmt_unimplemented}, @@ -293,7 +298,7 @@ mgmt_handler_t mgmt_handlers[] = { { .cmd = NULL }, }; -static void mgmt_help (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { +static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { size_t msg_len; mgmt_handler_t *handler; @@ -309,12 +314,11 @@ static void mgmt_help (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in "\"_type\":\"row\"," "\"cmd\":\"%s\"," "\"help\":\"%s\"}\n", - tag, + req->tag, handler->cmd, handler->help); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(req, udp_buf, msg_len); } } @@ -325,32 +329,30 @@ static void mgmt_help (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in * Reads are not dangerous, so they are simply allowed * Writes are possibly dangerous, so they need a fake password */ -static int mgmt_auth (n2n_edge_t *eee, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *auth, char *argv0, char *argv) { +static int mgmt_auth (mgmt_req_t *req, char *auth, char *argv0, char *argv) { if(auth) { /* If we have an auth key, it must match */ - if(eee->conf.mgmt_password_hash == pearson_hash_64((uint8_t*)auth, strlen(auth))) { + if(req->eee->conf.mgmt_password_hash == pearson_hash_64((uint8_t*)auth, strlen(auth))) { return 1; } return 0; } /* if we dont have an auth key, we can still read */ - if(type == N2N_MGMT_READ) { + if(req->type == N2N_MGMT_READ) { return 1; } return 0; } -static void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock) { +static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { char cmdlinebuf[80]; - enum n2n_mgmt_type type; char *typechar; char *options; char *argv0; char *argv; - char *tag; char *flagstr; int flags; char *auth; @@ -364,31 +366,32 @@ static void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockadd traceEvent(TRACE_DEBUG, "mgmt json %s", cmdlinebuf); typechar = strtok(cmdlinebuf, " \r\n"); + req->tag = "-1"; if(!typechar) { /* should not happen */ - mgmt_error(eee, udp_buf, sender_sock, "-1", "notype"); + mgmt_error(req, udp_buf, "notype"); return; } if(*typechar == 'r') { - type=N2N_MGMT_READ; + req->type=N2N_MGMT_READ; } else if(*typechar == 'w') { - type=N2N_MGMT_WRITE; + req->type=N2N_MGMT_WRITE; } else { /* dunno how we got here */ - mgmt_error(eee, udp_buf, sender_sock, "-1", "badtype"); + mgmt_error(req, udp_buf, "badtype"); return; } /* Extract the tag to use in all reply packets */ options = strtok(NULL, " \r\n"); if(!options) { - mgmt_error(eee, udp_buf, sender_sock, "-1", "nooptions"); + mgmt_error(req, udp_buf, "nooptions"); return; } argv0 = strtok(NULL, " \r\n"); if(!argv0) { - mgmt_error(eee, udp_buf, sender_sock, "-1", "nocmd"); + mgmt_error(req, udp_buf, "nocmd"); return; } @@ -401,7 +404,7 @@ static void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockadd /* * There might be an auth token mixed in with the tag */ - tag = strtok(options, ":"); + req->tag = strtok(options, ":"); flagstr = strtok(NULL, ":"); if(flagstr) { flags = strtoul(flagstr, NULL, 16); @@ -416,8 +419,8 @@ static void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockadd auth = NULL; } - if(!mgmt_auth(eee, sender_sock, type, auth, argv0, argv)) { - mgmt_error(eee, udp_buf, sender_sock, tag, "badauth"); + if(!mgmt_auth(req, auth, argv0, argv)) { + mgmt_error(req, udp_buf, "badauth"); return; } @@ -427,12 +430,12 @@ static void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockadd } } if(!handler->cmd) { - mgmt_error(eee, udp_buf, sender_sock, tag, "unknowncmd"); + mgmt_error(req, udp_buf, "unknowncmd"); return; } - if((type==N2N_MGMT_WRITE) && !(handler->flags & FLAG_WROK)) { - mgmt_error(eee, udp_buf, sender_sock, tag, "readonly"); + if((req->type==N2N_MGMT_WRITE) && !(handler->flags & FLAG_WROK)) { + mgmt_error(req, udp_buf, "readonly"); return; } @@ -443,16 +446,14 @@ static void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockadd * - do we care? */ msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, - "{\"_tag\":\"%s\",\"_type\":\"begin\",\"cmd\":\"%s\"}\n", tag, argv0); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + "{\"_tag\":\"%s\",\"_type\":\"begin\",\"cmd\":\"%s\"}\n", req->tag, argv0); + send_reply(req, udp_buf, msg_len); - handler->func(eee, udp_buf, sender_sock, type, tag, argv0, argv); + handler->func(req, udp_buf, argv0, argv); msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, - "{\"_tag\":\"%s\",\"_type\":\"end\"}\n", tag); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + "{\"_tag\":\"%s\",\"_type\":\"end\"}\n", req->tag); + send_reply(req, udp_buf, msg_len); return; } @@ -463,7 +464,7 @@ void readFromMgmtSocket (n2n_edge_t *eee) { char udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ ssize_t recvlen; /* ssize_t sendlen; */ - struct sockaddr_in sender_sock; + mgmt_req_t req; socklen_t i; size_t msg_len; time_t now; @@ -480,11 +481,12 @@ void readFromMgmtSocket (n2n_edge_t *eee) { uint32_t num = 0; selection_criterion_str_t sel_buf; + req.eee = eee; now = time(NULL); - i = sizeof(sender_sock); + i = sizeof(req.sender_sock); recvlen = recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0 /*flags*/, - (struct sockaddr *) &sender_sock, (socklen_t *) &i); + (struct sockaddr *) &req.sender_sock, (socklen_t *) &i); if(recvlen < 0) { traceEvent(TRACE_WARNING, "mgmt recvfrom failed: %d - %s", errno, strerror(errno)); @@ -507,8 +509,7 @@ void readFromMgmtSocket (n2n_edge_t *eee) { "\tw ... | start update with JSON reply\n" "\t | Display statistics\n\n"); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(&req, udp_buf, msg_len); return; } @@ -527,8 +528,7 @@ void readFromMgmtSocket (n2n_edge_t *eee) { msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), "> +OK traceLevel=%u\n", (unsigned int) getTraceLevel()); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(&req, udp_buf, msg_len); return; } @@ -547,14 +547,13 @@ void readFromMgmtSocket (n2n_edge_t *eee) { traceEvent(TRACE_NORMAL, "-verb traceLevel=%u", (unsigned int) getTraceLevel()); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(&req, udp_buf, msg_len); return; } if((udp_buf[0] == 'r' || udp_buf[0] == 'w') && (udp_buf[1] == ' ')) { /* this is a JSON request */ - handleMgmtJson(eee, udp_buf, sender_sock); + handleMgmtJson(&req, udp_buf, recvlen); return; } @@ -586,8 +585,7 @@ void readFromMgmtSocket (n2n_edge_t *eee) { peer->dev_desc, (peer->last_seen) ? time_buf : ""); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(&req, udp_buf, msg_len); msg_len = 0; } @@ -610,8 +608,7 @@ void readFromMgmtSocket (n2n_edge_t *eee) { peer->dev_desc, (peer->last_seen) ? time_buf : ""); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(&req, udp_buf, msg_len); msg_len = 0; } @@ -636,8 +633,7 @@ void readFromMgmtSocket (n2n_edge_t *eee) { (peer->last_seen) ? time_buf : "", (peer->uptime) ? uptime_buf : ""); - sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(&req, udp_buf, msg_len); msg_len = 0; } @@ -683,6 +679,5 @@ void readFromMgmtSocket (n2n_edge_t *eee) { msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), "\nType \"help\" to see more commands.\n\n"); - /* sendlen = */ sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, - (struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); + send_reply(&req, udp_buf, msg_len); } From 5bcc6fe67a27cb99ceb7e36bd378a1d9812bf7da Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 6 Nov 2021 21:00:36 +0000 Subject: [PATCH 24/38] Tracebacks contain full paths and cannot be part of the expected test data --- scripts/test_integration_edge.sh | 3 ++- tests/test_integration_edge.sh.expected | 15 +-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/scripts/test_integration_edge.sh b/scripts/test_integration_edge.sh index 50ae6dd..93a5424 100755 --- a/scripts/test_integration_edge.sh +++ b/scripts/test_integration_edge.sh @@ -36,7 +36,8 @@ docmd ${TOPDIR}/scripts/n2n-ctl edges --raw # - uptime docmd ${TOPDIR}/scripts/n2n-ctl verbose -docmd ${TOPDIR}/scripts/n2n-ctl --write verbose 1 2>&1 +docmd ${TOPDIR}/scripts/n2n-ctl --write verbose 1 2>/dev/null +echo $? docmd ${TOPDIR}/scripts/n2n-ctl -k $AUTH --write verbose 1 # looks strange, but we are querying the state of the "stop" verb diff --git a/tests/test_integration_edge.sh.expected b/tests/test_integration_edge.sh.expected index 8e13193..f8a009f 100644 --- a/tests/test_integration_edge.sh.expected +++ b/tests/test_integration_edge.sh.expected @@ -42,21 +42,8 @@ ] ### -Traceback (most recent call last): - File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 258, in - main() - File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 249, in main - result = func(rpc, args) - File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 205, in subcmd_default - rows = rpc.write(cmdline) - File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 106, in write - return self._call('w', cmdline) - File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 100, in _call - return self._rx(tagstr) - File "/home/hamish/r/n2n/./scripts/n2n-ctl", line 53, in _rx - raise ValueError('Error: {}'.format(data['error'])) -ValueError: Error: badauth +0 ### [ { From 40773b4e4d66e1d90c9263e3ee2e2e5d7bff7015 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sun, 7 Nov 2021 15:16:10 +0000 Subject: [PATCH 25/38] Ensure we have a local copy of the tag in our request structure - which will be useful for the event framework --- doc/ManagementAPI.md | 5 +++-- src/edge_management.c | 13 ++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/ManagementAPI.md b/doc/ManagementAPI.md index 617e345..3ad0744 100644 --- a/doc/ManagementAPI.md +++ b/doc/ManagementAPI.md @@ -83,7 +83,8 @@ SubFields: Each request provides a tag value. Any non error reply associated with this request will include this tag value, allowing all related messages to be -collected within the client. +collected within the client. The tag will be truncated if needed by the +daemon, but there will be at least 8 octets of space available. Where possible, the error replies will also include this tag, however some errors occur before the tag is parsed. @@ -131,7 +132,7 @@ containing a fragment of information related to the entire reply. There are two keys in each dictionary containing metadata. First is the `_tag`, containing the Message Tag from the original request. -Second is the `_type` whic identifies the expected contents of this +Second is the `_type` which identifies the expected contents of this packet. ### `_type: error` diff --git a/src/edge_management.c b/src/edge_management.c index be8a8c4..3054d40 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -25,7 +25,7 @@ typedef struct mgmt_req { n2n_edge_t *eee; enum n2n_mgmt_type type; - char *tag; + char tag[10]; struct sockaddr_in sender_sock; } mgmt_req_t; @@ -359,6 +359,11 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { mgmt_handler_t *handler; size_t msg_len; + /* Initialise the tag field until we extract it from the cmdline */ + req->tag[0] = '-'; + req->tag[1] = '1'; + req->tag[2] = '\0'; + /* save a copy of the commandline before we reuse the udp_buf */ strncpy(cmdlinebuf, udp_buf, sizeof(cmdlinebuf)-1); cmdlinebuf[sizeof(cmdlinebuf)-1] = 0; @@ -366,7 +371,6 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { traceEvent(TRACE_DEBUG, "mgmt json %s", cmdlinebuf); typechar = strtok(cmdlinebuf, " \r\n"); - req->tag = "-1"; if(!typechar) { /* should not happen */ mgmt_error(req, udp_buf, "notype"); @@ -404,7 +408,10 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { /* * There might be an auth token mixed in with the tag */ - req->tag = strtok(options, ":"); + char *tagp = strtok(options, ":"); + strncpy(req->tag, tagp, sizeof(req->tag)-1); + req->tag[sizeof(req->tag)-1] = '\0'; + flagstr = strtok(NULL, ":"); if(flagstr) { flags = strtoul(flagstr, NULL, 16); From 3e2c2d63bcdb4df74c7942112dea3304197b03f6 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sun, 7 Nov 2021 16:00:36 +0000 Subject: [PATCH 26/38] Add basic structures to be used for pubsub --- src/edge_management.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/edge_management.c b/src/edge_management.c index 3054d40..74cefde 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -29,20 +29,36 @@ typedef struct mgmt_req { struct sockaddr_in sender_sock; } mgmt_req_t; +/* + * Read/Write handlers are defined in this structure + */ #define FLAG_WROK 1 typedef struct mgmt_handler { int flags; char *cmd; char *help; - void (*func)(mgmt_req_t *reg, char *udp_buf, char *argv0, char *argv); + void (*func)(mgmt_req_t *req, char *udp_buf, char *argv0, char *argv); } mgmt_handler_t; +/* + * Event topic names are defined in this structure + */ +typedef struct mgmt_events { + int topic; // topic number define + char *cmd; + char *help; +} mgmt_events_t; + static void send_reply (mgmt_req_t *req, char *udp_buf, size_t msg_len) { // TODO: error handling sendto(req->eee->udp_mgmt_sock, udp_buf, msg_len, 0, (struct sockaddr *) &req->sender_sock, sizeof(struct sockaddr_in)); } +static void event_debug (mgmt_req_t *req, char *udp_buf) { + send_reply(req, "test", 4); +} + static void mgmt_error (mgmt_req_t *req, char *udp_buf, char *msg) { size_t msg_len; msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, @@ -282,9 +298,10 @@ static void mgmt_unimplemented (mgmt_req_t *req, char *udp_buf, char *argv0, cha mgmt_error(req, udp_buf, "unimplemented"); } +// Forward define so we can include this in the mgmt_handlers[] table static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv); -mgmt_handler_t mgmt_handlers[] = { +static mgmt_handler_t mgmt_handlers[] = { { .cmd = "reload_communities", .flags = FLAG_WROK, .help = "Reserved for supernode", .func = mgmt_unimplemented}, { .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop}, @@ -295,6 +312,21 @@ mgmt_handler_t mgmt_handlers[] = { { .cmd = "timestamps", .help = "Event timestamps", .func = mgmt_timestamps}, { .cmd = "packetstats", .help = "traffic counters", .func = mgmt_packetstats}, { .cmd = "help", .flags = FLAG_WROK, .help = "Show JSON commands", .func = mgmt_help}, + // TODO: help_events + { .cmd = NULL }, +}; + +/* Current subscriber for each event topic */ +static mgmt_req_t *mgmt_event_subscribers[10]; + +/* Map topic number to function */ +static const void (*mgmt_events[])(mgmt_req_t *req, char *udp_buf) = { + [0] = event_debug, +}; + +/* Allow help and subscriptions to use topic name */ +static mgmt_events_t mgmt_event_names[] = { + { .cmd = "debug", .topic = 0, .help = "All events - for event debugging"}, { .cmd = NULL }, }; @@ -514,6 +546,7 @@ void readFromMgmtSocket (n2n_edge_t *eee) { "\t-verb | Decrease verbosity of logging\n" "\tr ... | start query with JSON reply\n" "\tw ... | start update with JSON reply\n" + "\ts ... | subscribe to event channel JSON reply\n" "\t | Display statistics\n\n"); send_reply(&req, udp_buf, msg_len); @@ -558,7 +591,7 @@ void readFromMgmtSocket (n2n_edge_t *eee) { return; } - if((udp_buf[0] == 'r' || udp_buf[0] == 'w') && (udp_buf[1] == ' ')) { + if((udp_buf[0] >= 'a' && udp_buf[0] <= 'z') && (udp_buf[1] == ' ')) { /* this is a JSON request */ handleMgmtJson(&req, udp_buf, recvlen); return; From 06b8f1a08f096cbb23fc6428749c475a1e37ce99 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sun, 7 Nov 2021 19:19:36 +0000 Subject: [PATCH 27/38] Refactor management command list to allow it to be declared const with no warnings --- src/edge_management.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/edge_management.c b/src/edge_management.c index 74cefde..eea5f22 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -301,7 +301,7 @@ static void mgmt_unimplemented (mgmt_req_t *req, char *udp_buf, char *argv0, cha // Forward define so we can include this in the mgmt_handlers[] table static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv); -static mgmt_handler_t mgmt_handlers[] = { +static const mgmt_handler_t mgmt_handlers[] = { { .cmd = "reload_communities", .flags = FLAG_WROK, .help = "Reserved for supernode", .func = mgmt_unimplemented}, { .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop}, @@ -313,7 +313,6 @@ static mgmt_handler_t mgmt_handlers[] = { { .cmd = "packetstats", .help = "traffic counters", .func = mgmt_packetstats}, { .cmd = "help", .flags = FLAG_WROK, .help = "Show JSON commands", .func = mgmt_help}, // TODO: help_events - { .cmd = NULL }, }; /* Current subscriber for each event topic */ @@ -332,14 +331,15 @@ static mgmt_events_t mgmt_event_names[] = { static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { size_t msg_len; - mgmt_handler_t *handler; /* * Even though this command is readonly, we deliberately do not check * the type - allowing help replies to both read and write requests */ - for( handler=mgmt_handlers; handler->cmd; handler++ ) { + int i; + int nr_handlers = sizeof(mgmt_handlers) / sizeof(mgmt_handler_t); + for( i=0; i < nr_handlers; i++ ) { msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, "{" "\"_tag\":\"%s\"," @@ -347,8 +347,8 @@ static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) "\"cmd\":\"%s\"," "\"help\":\"%s\"}\n", req->tag, - handler->cmd, - handler->help); + mgmt_handlers[i].cmd, + mgmt_handlers[i].help); send_reply(req, udp_buf, msg_len); } @@ -388,7 +388,6 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { char *flagstr; int flags; char *auth; - mgmt_handler_t *handler; size_t msg_len; /* Initialise the tag field until we extract it from the cmdline */ @@ -463,17 +462,19 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { return; } - for( handler=mgmt_handlers; handler->cmd; handler++ ) { - if(0 == strcmp(handler->cmd, argv0)) { + int handler; + int nr_handlers = sizeof(mgmt_handlers) / sizeof(mgmt_handler_t); + for( handler=0; handler < nr_handlers; handler++ ) { + if(0 == strcmp(mgmt_handlers[handler].cmd, argv0)) { break; } } - if(!handler->cmd) { + if(handler >= nr_handlers) { mgmt_error(req, udp_buf, "unknowncmd"); return; } - if((req->type==N2N_MGMT_WRITE) && !(handler->flags & FLAG_WROK)) { + if((req->type==N2N_MGMT_WRITE) && !(mgmt_handlers[handler].flags & FLAG_WROK)) { mgmt_error(req, udp_buf, "readonly"); return; } @@ -488,7 +489,7 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { "{\"_tag\":\"%s\",\"_type\":\"begin\",\"cmd\":\"%s\"}\n", req->tag, argv0); send_reply(req, udp_buf, msg_len); - handler->func(req, udp_buf, argv0, argv); + mgmt_handlers[handler].func(req, udp_buf, argv0, argv); msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, "{\"_tag\":\"%s\",\"_type\":\"end\"}\n", req->tag); From e3899d1b760403fa1615c46e9fe0114b9fbe164e Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sun, 28 Nov 2021 22:10:07 +1100 Subject: [PATCH 28/38] Give a magic number a better name --- src/edge_management.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/edge_management.c b/src/edge_management.c index eea5f22..efd90b0 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -315,8 +315,10 @@ static const mgmt_handler_t mgmt_handlers[] = { // TODO: help_events }; +#define MAX_TOPICS 10 + /* Current subscriber for each event topic */ -static mgmt_req_t *mgmt_event_subscribers[10]; +static mgmt_req_t *mgmt_event_subscribers[MAX_TOPICS]; /* Map topic number to function */ static const void (*mgmt_events[])(mgmt_req_t *req, char *udp_buf) = { From 3fd1dc5fa841c7af5f9e234cc60516e90a153d35 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sun, 28 Nov 2021 22:13:47 +1100 Subject: [PATCH 29/38] keep private enum definition local to the management code --- include/n2n_define.h | 5 ----- src/edge_management.c | 5 +++++ src/sn_management.c | 5 +++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/n2n_define.h b/include/n2n_define.h index cdee5da..451dacb 100644 --- a/include/n2n_define.h +++ b/include/n2n_define.h @@ -121,11 +121,6 @@ enum sn_purge {SN_PURGEABLE = 0, SN_UNPURGEABLE = 1}; #define N2N_EDGE_MGMT_PORT 5644 #define N2N_SN_MGMT_PORT 5645 -enum n2n_mgmt_type { - N2N_MGMT_READ = 0, - N2N_MGMT_WRITE = 1, -}; - #define N2N_MGMT_PASSWORD "n2n" /* default password for management port access (so far, json only) */ diff --git a/src/edge_management.c b/src/edge_management.c index efd90b0..018c8a5 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -19,6 +19,11 @@ #include "n2n.h" #include "edge_utils_win32.h" +enum n2n_mgmt_type { + N2N_MGMT_READ = 0, + N2N_MGMT_WRITE = 1, +}; + /* * Everything needed to reply to a request */ diff --git a/src/sn_management.c b/src/sn_management.c index e4aa7aa..63a2b31 100644 --- a/src/sn_management.c +++ b/src/sn_management.c @@ -26,6 +26,11 @@ int load_allowed_sn_community (n2n_sn_t *sss); /* defined in sn_utils.c */ +enum n2n_mgmt_type { + N2N_MGMT_READ = 0, + N2N_MGMT_WRITE = 1, +}; + #define FLAG_WROK 1 typedef struct mgmt_handler { int flags; From e2a33b7571e6a9b979648002549d5ae0d91c1f81 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sun, 28 Nov 2021 23:10:17 +1100 Subject: [PATCH 30/38] Implement initial help command for subscription topics --- src/edge_management.c | 53 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/edge_management.c b/src/edge_management.c index 018c8a5..a67e59d 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -20,8 +20,10 @@ #include "edge_utils_win32.h" enum n2n_mgmt_type { - N2N_MGMT_READ = 0, - N2N_MGMT_WRITE = 1, + N2N_MGMT_UNKNOWN = 0, + N2N_MGMT_READ = 1, + N2N_MGMT_WRITE = 2, + N2N_MGMT_SUB = 3, }; /* @@ -305,6 +307,7 @@ static void mgmt_unimplemented (mgmt_req_t *req, char *udp_buf, char *argv0, cha // Forward define so we can include this in the mgmt_handlers[] table static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv); +static void mgmt_help_events (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv); static const mgmt_handler_t mgmt_handlers[] = { { .cmd = "reload_communities", .flags = FLAG_WROK, .help = "Reserved for supernode", .func = mgmt_unimplemented}, @@ -317,13 +320,13 @@ static const mgmt_handler_t mgmt_handlers[] = { { .cmd = "timestamps", .help = "Event timestamps", .func = mgmt_timestamps}, { .cmd = "packetstats", .help = "traffic counters", .func = mgmt_packetstats}, { .cmd = "help", .flags = FLAG_WROK, .help = "Show JSON commands", .func = mgmt_help}, - // TODO: help_events + { .cmd = "help.events", .help = "Show available Subscribe topics", .func = mgmt_help_events}, }; -#define MAX_TOPICS 10 - /* Current subscriber for each event topic */ -static mgmt_req_t *mgmt_event_subscribers[MAX_TOPICS]; +static mgmt_req_t mgmt_event_subscribers[] = { + [0] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, +}; /* Map topic number to function */ static const void (*mgmt_events[])(mgmt_req_t *req, char *udp_buf) = { @@ -331,11 +334,37 @@ static const void (*mgmt_events[])(mgmt_req_t *req, char *udp_buf) = { }; /* Allow help and subscriptions to use topic name */ -static mgmt_events_t mgmt_event_names[] = { +static const mgmt_events_t mgmt_event_names[] = { { .cmd = "debug", .topic = 0, .help = "All events - for event debugging"}, - { .cmd = NULL }, }; +static void mgmt_help_events (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { + size_t msg_len; + + int i; + int nr_handlers = sizeof(mgmt_event_names) / sizeof(mgmt_events_t); + for( i=0; i < nr_handlers; i++ ) { + int topic = mgmt_event_names[i].topic; + mgmt_req_t *sub = &mgmt_event_subscribers[topic]; + + msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"row\"," + "\"topic\":\"%s\"," + "\"tag\":\"%s\"," + // "\"sockaddr\":\"%s\"," + "\"help\":\"%s\"}\n", + req->tag, + mgmt_event_names[i].cmd, + sub->tag, + // "FIXME", + mgmt_event_names[i].help); + + send_reply(req, udp_buf, msg_len); + } +} + static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { size_t msg_len; @@ -418,8 +447,9 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { req->type=N2N_MGMT_READ; } else if(*typechar == 'w') { req->type=N2N_MGMT_WRITE; + } else if(*typechar == 's') { + req->type=N2N_MGMT_SUB; } else { - /* dunno how we got here */ mgmt_error(req, udp_buf, "badtype"); return; } @@ -469,6 +499,11 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { return; } + if(req->type == N2N_MGMT_SUB) { + mgmt_error(req, udp_buf, "unimplemented"); + return; + } + int handler; int nr_handlers = sizeof(mgmt_handlers) / sizeof(mgmt_handler_t); for( handler=0; handler < nr_handlers; handler++ ) { From 64e5329bca5cfe7dfb1e5605c53535cd1db5e881 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sun, 28 Nov 2021 23:47:13 +1100 Subject: [PATCH 31/38] Refactor command handler lookup into a macro for reuse in the topic lookup --- src/edge_management.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/edge_management.c b/src/edge_management.c index a67e59d..85b8be3 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -56,6 +56,20 @@ typedef struct mgmt_events { char *help; } mgmt_events_t; +// Lookup the index of matching argv0 in a cmd list +// store index in "Result", or -1 for not found +#define lookup_handler(Result, list, argv0) do { \ + int nr_max = sizeof(list) / sizeof(list[0]); \ + for( Result=0; Result < nr_max; Result++ ) { \ + if(0 == strcmp(list[Result].cmd, argv0)) { \ + break; \ + } \ + } \ + if( Result >= nr_max ) { \ + Result = -1; \ + } \ +} while(0) + static void send_reply (mgmt_req_t *req, char *udp_buf, size_t msg_len) { // TODO: error handling sendto(req->eee->udp_mgmt_sock, udp_buf, msg_len, 0, @@ -505,13 +519,8 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { } int handler; - int nr_handlers = sizeof(mgmt_handlers) / sizeof(mgmt_handler_t); - for( handler=0; handler < nr_handlers; handler++ ) { - if(0 == strcmp(mgmt_handlers[handler].cmd, argv0)) { - break; - } - } - if(handler >= nr_handlers) { + lookup_handler(handler, mgmt_handlers, argv0); + if(handler == -1) { mgmt_error(req, udp_buf, "unknowncmd"); return; } From 58fedeed95ed7b082f5bfb7c63d1bc7f343dcec1 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Mon, 29 Nov 2021 00:30:10 +1100 Subject: [PATCH 32/38] Add a helper for simple 1 arg json replies --- src/edge_management.c | 78 ++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/src/edge_management.c b/src/edge_management.c index 85b8be3..05539f2 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -76,42 +76,50 @@ static void send_reply (mgmt_req_t *req, char *udp_buf, size_t msg_len) { (struct sockaddr *) &req->sender_sock, sizeof(struct sockaddr_in)); } +static void send_json_1str (mgmt_req_t *req, char *udp_buf, char *_type, char *key, char *val) { + size_t msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"%s\"," + "\"%s\":\"%s\"}\n", + req->tag, + _type, + key, + val); + send_reply(req, udp_buf, msg_len); +} + +static void send_json_1uint (mgmt_req_t *req, char *udp_buf, char *_type, char *key, unsigned int val) { + size_t msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"%s\"," + "\"%s\":%u}\n", + req->tag, + _type, + key, + val); + send_reply(req, udp_buf, msg_len); +} + static void event_debug (mgmt_req_t *req, char *udp_buf) { send_reply(req, "test", 4); } static void mgmt_error (mgmt_req_t *req, char *udp_buf, char *msg) { - size_t msg_len; - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, - "{" - "\"_tag\":\"%s\"," - "\"_type\":\"error\"," - "\"error\":\"%s\"}\n", - req->tag, - msg); - send_reply(req, udp_buf, msg_len); + send_json_1str(req, udp_buf, "error", "error", msg); } static void mgmt_stop (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { - size_t msg_len; if(req->type==N2N_MGMT_WRITE) { *req->eee->keep_running = 0; } - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, - "{" - "\"_tag\":\"%s\"," - "\"_type\":\"row\"," - "\"keep_running\":%u}\n", - req->tag, - *req->eee->keep_running); - - send_reply(req, udp_buf, msg_len); + send_json_1uint(req, udp_buf, "row", "keep_running", *req->eee->keep_running); } static void mgmt_verbose (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { - size_t msg_len; if(req->type==N2N_MGMT_WRITE) { if(argv) { @@ -119,34 +127,17 @@ static void mgmt_verbose (mgmt_req_t *req, char *udp_buf, char *argv0, char *arg } } - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, - "{" - "\"_tag\":\"%s\"," - "\"_type\":\"row\"," - "\"traceLevel\":%u}\n", - req->tag, - getTraceLevel()); - - send_reply(req, udp_buf, msg_len); + send_json_1uint(req, udp_buf, "row", "traceLevel", getTraceLevel()); } static void mgmt_communities (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { - size_t msg_len; if(req->eee->conf.header_encryption != HEADER_ENCRYPTION_NONE) { mgmt_error(req, udp_buf, "noaccess"); return; } - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, - "{" - "\"_tag\":\"%s\"," - "\"_type\":\"row\"," - "\"community\":\"%s\"}", - req->tag, - req->eee->conf.community_name); - - send_reply(req, udp_buf, msg_len); + send_json_1str(req, udp_buf, "row", "community", req->eee->conf.community_name); } static void mgmt_supernodes (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { @@ -438,7 +429,6 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { char *flagstr; int flags; char *auth; - size_t msg_len; /* Initialise the tag field until we extract it from the cmdline */ req->tag[0] = '-'; @@ -536,15 +526,11 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { * that make our JSON invalid. * - do we care? */ - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, - "{\"_tag\":\"%s\",\"_type\":\"begin\",\"cmd\":\"%s\"}\n", req->tag, argv0); - send_reply(req, udp_buf, msg_len); + send_json_1str(req, udp_buf, "begin", "cmd", argv0); mgmt_handlers[handler].func(req, udp_buf, argv0, argv); - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, - "{\"_tag\":\"%s\",\"_type\":\"end\"}\n", req->tag); - send_reply(req, udp_buf, msg_len); + send_json_1str(req, udp_buf, "end", "cmd", argv0); return; } From 9c77d0becd393b5ca9c8103fca4552b65477a0f1 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Mon, 29 Nov 2021 00:33:21 +1100 Subject: [PATCH 33/38] Address warning --- src/edge_management.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edge_management.c b/src/edge_management.c index 05539f2..a6ce391 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -137,7 +137,7 @@ static void mgmt_communities (mgmt_req_t *req, char *udp_buf, char *argv0, char return; } - send_json_1str(req, udp_buf, "row", "community", req->eee->conf.community_name); + send_json_1str(req, udp_buf, "row", "community", (char *)req->eee->conf.community_name); } static void mgmt_supernodes (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { From 598ce63981fb6e7e9a1842f5c5f0f17e6881a3d9 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Tue, 30 Nov 2021 21:33:54 +1100 Subject: [PATCH 34/38] Use getnameinfo to show the subscribed socket details --- src/edge_management.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/edge_management.c b/src/edge_management.c index a6ce391..a69ac31 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -351,6 +351,21 @@ static void mgmt_help_events (mgmt_req_t *req, char *udp_buf, char *argv0, char for( i=0; i < nr_handlers; i++ ) { int topic = mgmt_event_names[i].topic; mgmt_req_t *sub = &mgmt_event_subscribers[topic]; + char host[40]; + char serv[6]; + + if(getnameinfo( + (struct sockaddr *)&sub->sender_sock, sizeof(sub->sender_sock), + host, sizeof(host), + serv, sizeof(serv), + NI_NUMERICHOST|NI_NUMERICSERV) != 0) { + host[0] = '?'; + host[1] = 0; + serv[0] = '?'; + serv[1] = 0; + } + + // TODO: handle a topic with no subscribers more cleanly msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, "{" @@ -358,12 +373,12 @@ static void mgmt_help_events (mgmt_req_t *req, char *udp_buf, char *argv0, char "\"_type\":\"row\"," "\"topic\":\"%s\"," "\"tag\":\"%s\"," - // "\"sockaddr\":\"%s\"," + "\"sockaddr\":\"%s:%s\"," "\"help\":\"%s\"}\n", req->tag, mgmt_event_names[i].cmd, sub->tag, - // "FIXME", + host, serv, mgmt_event_names[i].help); send_reply(req, udp_buf, msg_len); From 509a8bcd14170487384ec3691ed8b5aa288008ef Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Tue, 30 Nov 2021 22:08:22 +0930 Subject: [PATCH 35/38] Add a buffer object with a known size field to replace multiple hardcoded N2N_PKT_BUF_SIZE --- src/edge_management.c | 201 +++++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 90 deletions(-) diff --git a/src/edge_management.c b/src/edge_management.c index a69ac31..1aff29b 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -19,6 +19,16 @@ #include "n2n.h" #include "edge_utils_win32.h" +typedef struct strbuf { + size_t size; + char str[]; +} strbuf_t; + +#define STRBUF_INIT(buf,p) do { \ + buf = (void *)p; \ + buf->size = sizeof(*p) - sizeof(size_t); \ +} while(0) + enum n2n_mgmt_type { N2N_MGMT_UNKNOWN = 0, N2N_MGMT_READ = 1, @@ -44,7 +54,7 @@ typedef struct mgmt_handler { int flags; char *cmd; char *help; - void (*func)(mgmt_req_t *req, char *udp_buf, char *argv0, char *argv); + void (*func)(mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv); } mgmt_handler_t; /* @@ -70,14 +80,14 @@ typedef struct mgmt_events { } \ } while(0) -static void send_reply (mgmt_req_t *req, char *udp_buf, size_t msg_len) { +static void send_reply (mgmt_req_t *req, strbuf_t *buf, size_t msg_len) { // TODO: error handling - sendto(req->eee->udp_mgmt_sock, udp_buf, msg_len, 0, + sendto(req->eee->udp_mgmt_sock, buf->str, msg_len, 0, (struct sockaddr *) &req->sender_sock, sizeof(struct sockaddr_in)); } -static void send_json_1str (mgmt_req_t *req, char *udp_buf, char *_type, char *key, char *val) { - size_t msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, +static void send_json_1str (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, char *val) { + size_t msg_len = snprintf(buf->str, buf->size, "{" "\"_tag\":\"%s\"," "\"_type\":\"%s\"," @@ -86,11 +96,11 @@ static void send_json_1str (mgmt_req_t *req, char *udp_buf, char *_type, char *k _type, key, val); - send_reply(req, udp_buf, msg_len); + send_reply(req, buf, msg_len); } -static void send_json_1uint (mgmt_req_t *req, char *udp_buf, char *_type, char *key, unsigned int val) { - size_t msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, +static void send_json_1uint (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, unsigned int val) { + size_t msg_len = snprintf(buf->str, buf->size, "{" "\"_tag\":\"%s\"," "\"_type\":\"%s\"," @@ -99,27 +109,27 @@ static void send_json_1uint (mgmt_req_t *req, char *udp_buf, char *_type, char * _type, key, val); - send_reply(req, udp_buf, msg_len); + send_reply(req, buf, msg_len); } -static void event_debug (mgmt_req_t *req, char *udp_buf) { - send_reply(req, "test", 4); +static void event_debug (mgmt_req_t *req, strbuf_t *buf) { + send_json_1str(req, buf, "event", "test", "test"); } -static void mgmt_error (mgmt_req_t *req, char *udp_buf, char *msg) { - send_json_1str(req, udp_buf, "error", "error", msg); +static void mgmt_error (mgmt_req_t *req, strbuf_t *buf, char *msg) { + send_json_1str(req, buf, "error", "error", msg); } -static void mgmt_stop (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { +static void mgmt_stop (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { if(req->type==N2N_MGMT_WRITE) { *req->eee->keep_running = 0; } - send_json_1uint(req, udp_buf, "row", "keep_running", *req->eee->keep_running); + send_json_1uint(req, buf, "row", "keep_running", *req->eee->keep_running); } -static void mgmt_verbose (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { +static void mgmt_verbose (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { if(req->type==N2N_MGMT_WRITE) { if(argv) { @@ -127,20 +137,20 @@ static void mgmt_verbose (mgmt_req_t *req, char *udp_buf, char *argv0, char *arg } } - send_json_1uint(req, udp_buf, "row", "traceLevel", getTraceLevel()); + send_json_1uint(req, buf, "row", "traceLevel", getTraceLevel()); } -static void mgmt_communities (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { +static void mgmt_communities (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { if(req->eee->conf.header_encryption != HEADER_ENCRYPTION_NONE) { - mgmt_error(req, udp_buf, "noaccess"); + mgmt_error(req, buf, "noaccess"); return; } - send_json_1str(req, udp_buf, "row", "community", (char *)req->eee->conf.community_name); + send_json_1str(req, buf, "row", "community", (char *)req->eee->conf.community_name); } -static void mgmt_supernodes (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { +static void mgmt_supernodes (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { size_t msg_len; struct peer_info *peer, *tmpPeer; macstr_t mac_buf; @@ -156,7 +166,7 @@ static void mgmt_supernodes (mgmt_req_t *req, char *udp_buf, char *argv0, char * * - do we care? */ - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + msg_len = snprintf(buf->str, buf->size, "{" "\"_tag\":\"%s\"," "\"_type\":\"row\"," @@ -178,17 +188,17 @@ static void mgmt_supernodes (mgmt_req_t *req, char *udp_buf, char *argv0, char * peer->last_seen, peer->uptime); - send_reply(req, udp_buf, msg_len); + send_reply(req, buf, msg_len); } } -static void mgmt_edges_row (mgmt_req_t *req, char *udp_buf, struct peer_info *peer, char *mode) { +static void mgmt_edges_row (mgmt_req_t *req, strbuf_t *buf, struct peer_info *peer, char *mode) { size_t msg_len; macstr_t mac_buf; n2n_sock_str_t sockbuf; dec_ip_bit_str_t ip_bit_str = {'\0'}; - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + msg_len = snprintf(buf->str, buf->size, "{" "\"_tag\":\"%s\"," "\"_type\":\"row\"," @@ -214,27 +224,27 @@ static void mgmt_edges_row (mgmt_req_t *req, char *udp_buf, struct peer_info *pe peer->last_sent_query, peer->last_seen); - send_reply(req, udp_buf, msg_len); + send_reply(req, buf, msg_len); } -static void mgmt_edges (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { +static void mgmt_edges (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { struct peer_info *peer, *tmpPeer; // dump nodes with forwarding through supernodes HASH_ITER(hh, req->eee->pending_peers, peer, tmpPeer) { - mgmt_edges_row(req, udp_buf, peer, "pSp"); + mgmt_edges_row(req, buf, peer, "pSp"); } // dump peer-to-peer nodes HASH_ITER(hh, req->eee->known_peers, peer, tmpPeer) { - mgmt_edges_row(req, udp_buf, peer, "p2p"); + mgmt_edges_row(req, buf, peer, "p2p"); } } -static void mgmt_timestamps (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { +static void mgmt_timestamps (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { size_t msg_len; - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + msg_len = snprintf(buf->str, buf->size, "{" "\"_tag\":\"%s\"," "\"_type\":\"row\"," @@ -246,13 +256,13 @@ static void mgmt_timestamps (mgmt_req_t *req, char *udp_buf, char *argv0, char * req->eee->last_sup, req->eee->last_p2p); - send_reply(req, udp_buf, msg_len); + send_reply(req, buf, msg_len); } -static void mgmt_packetstats (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { +static void mgmt_packetstats (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { size_t msg_len; - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + msg_len = snprintf(buf->str, buf->size, "{" "\"_tag\":\"%s\"," "\"_type\":\"row\"," @@ -263,9 +273,9 @@ static void mgmt_packetstats (mgmt_req_t *req, char *udp_buf, char *argv0, char req->eee->transop.tx_cnt, req->eee->transop.rx_cnt); - send_reply(req, udp_buf, msg_len); + send_reply(req, buf, msg_len); - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + msg_len = snprintf(buf->str, buf->size, "{" "\"_tag\":\"%s\"," "\"_type\":\"row\"," @@ -276,9 +286,9 @@ static void mgmt_packetstats (mgmt_req_t *req, char *udp_buf, char *argv0, char req->eee->stats.tx_p2p, req->eee->stats.rx_p2p); - send_reply(req, udp_buf, msg_len); + send_reply(req, buf, msg_len); - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + msg_len = snprintf(buf->str, buf->size, "{" "\"_tag\":\"%s\"," "\"_type\":\"row\"," @@ -289,9 +299,9 @@ static void mgmt_packetstats (mgmt_req_t *req, char *udp_buf, char *argv0, char req->eee->stats.tx_sup, req->eee->stats.rx_sup); - send_reply(req, udp_buf, msg_len); + send_reply(req, buf, msg_len); - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + msg_len = snprintf(buf->str, buf->size, "{" "\"_tag\":\"%s\"," "\"_type\":\"row\"," @@ -302,17 +312,17 @@ static void mgmt_packetstats (mgmt_req_t *req, char *udp_buf, char *argv0, char req->eee->stats.tx_sup_broadcast, req->eee->stats.rx_sup_broadcast); - send_reply(req, udp_buf, msg_len); + send_reply(req, buf, msg_len); } -static void mgmt_unimplemented (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { +static void mgmt_unimplemented (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { - mgmt_error(req, udp_buf, "unimplemented"); + mgmt_error(req, buf, "unimplemented"); } // Forward define so we can include this in the mgmt_handlers[] table -static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv); -static void mgmt_help_events (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv); +static void mgmt_help (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv); +static void mgmt_help_events (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv); static const mgmt_handler_t mgmt_handlers[] = { { .cmd = "reload_communities", .flags = FLAG_WROK, .help = "Reserved for supernode", .func = mgmt_unimplemented}, @@ -334,7 +344,7 @@ static mgmt_req_t mgmt_event_subscribers[] = { }; /* Map topic number to function */ -static const void (*mgmt_events[])(mgmt_req_t *req, char *udp_buf) = { +static const void (*mgmt_events[])(mgmt_req_t *req, strbuf_t *buf) = { [0] = event_debug, }; @@ -343,7 +353,7 @@ static const mgmt_events_t mgmt_event_names[] = { { .cmd = "debug", .topic = 0, .help = "All events - for event debugging"}, }; -static void mgmt_help_events (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { +static void mgmt_help_events (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { size_t msg_len; int i; @@ -367,7 +377,7 @@ static void mgmt_help_events (mgmt_req_t *req, char *udp_buf, char *argv0, char // TODO: handle a topic with no subscribers more cleanly - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + msg_len = snprintf(buf->str, buf->size, "{" "\"_tag\":\"%s\"," "\"_type\":\"row\"," @@ -381,11 +391,11 @@ static void mgmt_help_events (mgmt_req_t *req, char *udp_buf, char *argv0, char host, serv, mgmt_event_names[i].help); - send_reply(req, udp_buf, msg_len); + send_reply(req, buf, msg_len); } } -static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) { +static void mgmt_help (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { size_t msg_len; /* @@ -396,7 +406,7 @@ static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) int i; int nr_handlers = sizeof(mgmt_handlers) / sizeof(mgmt_handler_t); for( i=0; i < nr_handlers; i++ ) { - msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, + msg_len = snprintf(buf->str, buf->size, "{" "\"_tag\":\"%s\"," "\"_type\":\"row\"," @@ -406,7 +416,7 @@ static void mgmt_help (mgmt_req_t *req, char *udp_buf, char *argv0, char *argv) mgmt_handlers[i].cmd, mgmt_handlers[i].help); - send_reply(req, udp_buf, msg_len); + send_reply(req, buf, msg_len); } } @@ -436,6 +446,7 @@ static int mgmt_auth (mgmt_req_t *req, char *auth, char *argv0, char *argv) { static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { + strbuf_t *buf; char cmdlinebuf[80]; char *typechar; char *options; @@ -456,10 +467,13 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { traceEvent(TRACE_DEBUG, "mgmt json %s", cmdlinebuf); + /* we reuse the buffer already on the stack for all our strings */ + STRBUF_INIT(buf, udp_buf); + typechar = strtok(cmdlinebuf, " \r\n"); if(!typechar) { /* should not happen */ - mgmt_error(req, udp_buf, "notype"); + mgmt_error(req, buf, "notype"); return; } if(*typechar == 'r') { @@ -469,20 +483,20 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { } else if(*typechar == 's') { req->type=N2N_MGMT_SUB; } else { - mgmt_error(req, udp_buf, "badtype"); + mgmt_error(req, buf, "badtype"); return; } /* Extract the tag to use in all reply packets */ options = strtok(NULL, " \r\n"); if(!options) { - mgmt_error(req, udp_buf, "nooptions"); + mgmt_error(req, buf, "nooptions"); return; } argv0 = strtok(NULL, " \r\n"); if(!argv0) { - mgmt_error(req, udp_buf, "nocmd"); + mgmt_error(req, buf, "nocmd"); return; } @@ -514,24 +528,24 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { } if(!mgmt_auth(req, auth, argv0, argv)) { - mgmt_error(req, udp_buf, "badauth"); + mgmt_error(req, buf, "badauth"); return; } if(req->type == N2N_MGMT_SUB) { - mgmt_error(req, udp_buf, "unimplemented"); + mgmt_error(req, buf, "unimplemented"); return; } int handler; lookup_handler(handler, mgmt_handlers, argv0); if(handler == -1) { - mgmt_error(req, udp_buf, "unknowncmd"); + mgmt_error(req, buf, "unknowncmd"); return; } if((req->type==N2N_MGMT_WRITE) && !(mgmt_handlers[handler].flags & FLAG_WROK)) { - mgmt_error(req, udp_buf, "readonly"); + mgmt_error(req, buf, "readonly"); return; } @@ -541,11 +555,11 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { * that make our JSON invalid. * - do we care? */ - send_json_1str(req, udp_buf, "begin", "cmd", argv0); + send_json_1str(req, buf, "begin", "cmd", argv0); - mgmt_handlers[handler].func(req, udp_buf, argv0, argv); + mgmt_handlers[handler].func(req, buf, argv0, argv); - send_json_1str(req, udp_buf, "end", "cmd", argv0); + send_json_1str(req, buf, "end", "cmd", argv0); return; } @@ -589,20 +603,20 @@ void readFromMgmtSocket (n2n_edge_t *eee) { udp_buf[recvlen] = 0; if((0 == memcmp(udp_buf, "help", 4)) || (0 == memcmp(udp_buf, "?", 1))) { - msg_len = 0; + strbuf_t *buf; + STRBUF_INIT(buf, &udp_buf); + msg_len = snprintf(buf->str, buf->size, + "Help for edge management console:\n" + "\tstop | Gracefully exit edge\n" + "\thelp | This help message\n" + "\t+verb | Increase verbosity of logging\n" + "\t-verb | Decrease verbosity of logging\n" + "\tr ... | start query with JSON reply\n" + "\tw ... | start update with JSON reply\n" + "\ts ... | subscribe to event channel JSON reply\n" + "\t | Display statistics\n\n"); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "Help for edge management console:\n" - "\tstop | Gracefully exit edge\n" - "\thelp | This help message\n" - "\t+verb | Increase verbosity of logging\n" - "\t-verb | Decrease verbosity of logging\n" - "\tr ... | start query with JSON reply\n" - "\tw ... | start update with JSON reply\n" - "\ts ... | subscribe to event channel JSON reply\n" - "\t | Display statistics\n\n"); - - send_reply(&req, udp_buf, msg_len); + send_reply(&req, buf, msg_len); return; } @@ -614,33 +628,36 @@ void readFromMgmtSocket (n2n_edge_t *eee) { } if(0 == memcmp(udp_buf, "+verb", 5)) { - msg_len = 0; setTraceLevel(getTraceLevel() + 1); traceEvent(TRACE_NORMAL, "+verb traceLevel=%u", (unsigned int) getTraceLevel()); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "> +OK traceLevel=%u\n", (unsigned int) getTraceLevel()); - send_reply(&req, udp_buf, msg_len); + strbuf_t *buf; + STRBUF_INIT(buf, &udp_buf); + msg_len = snprintf(buf->str, buf->size, + "> +OK traceLevel=%u\n", (unsigned int) getTraceLevel()); + + send_reply(&req, buf, msg_len); return; } if(0 == memcmp(udp_buf, "-verb", 5)) { - msg_len = 0; + strbuf_t *buf; + STRBUF_INIT(buf, &udp_buf); if(getTraceLevel() > 0) { setTraceLevel(getTraceLevel() - 1); - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "> -OK traceLevel=%u\n", getTraceLevel()); + msg_len = snprintf(buf->str, buf->size, + "> -OK traceLevel=%u\n", getTraceLevel()); } else { - msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), - "> -NOK traceLevel=%u\n", getTraceLevel()); + msg_len = snprintf(buf->str, buf->size, + "> -NOK traceLevel=%u\n", getTraceLevel()); } traceEvent(TRACE_NORMAL, "-verb traceLevel=%u", (unsigned int) getTraceLevel()); - send_reply(&req, udp_buf, msg_len); + send_reply(&req, buf, msg_len); return; } @@ -678,7 +695,8 @@ void readFromMgmtSocket (n2n_edge_t *eee) { peer->dev_desc, (peer->last_seen) ? time_buf : ""); - send_reply(&req, udp_buf, msg_len); + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)); msg_len = 0; } @@ -701,7 +719,8 @@ void readFromMgmtSocket (n2n_edge_t *eee) { peer->dev_desc, (peer->last_seen) ? time_buf : ""); - send_reply(&req, udp_buf, msg_len); + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)); msg_len = 0; } @@ -726,7 +745,8 @@ void readFromMgmtSocket (n2n_edge_t *eee) { (peer->last_seen) ? time_buf : "", (peer->uptime) ? uptime_buf : ""); - send_reply(&req, udp_buf, msg_len); + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)); msg_len = 0; } @@ -772,5 +792,6 @@ void readFromMgmtSocket (n2n_edge_t *eee) { msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len), "\nType \"help\" to see more commands.\n\n"); - send_reply(&req, udp_buf, msg_len); + sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, + (struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)); } From a40ed15d93030de84a4b404806f9cf1dc7965dda Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 5 Feb 2022 18:39:26 +0000 Subject: [PATCH 36/38] Add pubsub system to edge, with one example TEST channel --- doc/ManagementAPI.md | 65 ++++++++++++++++++++--- include/n2n.h | 2 + include/n2n_define.h | 5 ++ scripts/n2n-ctl | 71 ++++++++++++++++++++----- src/edge_management.c | 117 +++++++++++++++++++++++++++++++++--------- 5 files changed, 215 insertions(+), 45 deletions(-) diff --git a/doc/ManagementAPI.md b/doc/ManagementAPI.md index 3ad0744..3f179f4 100644 --- a/doc/ManagementAPI.md +++ b/doc/ManagementAPI.md @@ -1,6 +1,6 @@ # Management API -This document is focused on the machine readable API interfaces. +This document is focused on the machine readable API interfaces. Both the edge and the supernode provide a management interface UDP port. These interfaces have some documentation on their non machine readable @@ -48,7 +48,7 @@ but this is intended for debugging. The request is a single UDP packet containing one line of text with at least three space separated fields. Any text after the third field is available for -the API method to use for additional parameters +the API method to use for additional parameters Fields: - Message Type @@ -58,15 +58,23 @@ Fields: The maximum length of the entire line of text is 80 octets. +All request packets should generate a reply. However, this reply may simply +be an error. + ### Message Type -This is a single octet that is either "r" for a read (or query) method -call or "w" for a write (or change) method call. +This is a single octet specifying the type: + +- "r" for a read-only method (or one that does not need change permissions) +- "w" for a write method (or one that makes changes) +- "s" for a subscribe method to request this socket receive some events To simplify the interface, the reply from both read and write calls to the same method is expected to contain the same data. In the case of a write call, the reply will contain the new state after making the requested change. +The subscribe and events message flow works with a different set of messages. + ### Options The options field is a colon separated set of options for this request. Only @@ -90,8 +98,9 @@ Where possible, the error replies will also include this tag, however some errors occur before the tag is parsed. The tag is not interpreted by the daemon, it is simply echoed back in all -the replies. It is expected to be a short string that the client chooses -to be unique amongst all recent or still outstanding requests. +the replies. It is expected to be a short string that the client knows +will be unique amongst all recent, still outstanding or subscription requests +on a given socket. One possible client implementation is a number between 0 and 999, incremented for each request and wrapping around to zero when it is greater than 999. @@ -128,6 +137,9 @@ e.g: Each UDP packet in the reply is a complete and valid JSON dictionary containing a fragment of information related to the entire reply. +Reply packets are generated both in response to requests and whenever +an event is published to a subscribed channel. + ### Common metadata There are two keys in each dictionary containing metadata. First @@ -177,6 +189,47 @@ packets will be required. e.g: `{"_tag":"108","_type":"row","mode":"p2p","ip4addr":"10.135.98.84","macaddr":"86:56:21:E4:AA:39","sockaddr":"192.168.7.191:41701","desc":"client4","lastseen":1584682200}` +### `_type: subscribed` + +Signals that the subscription request has been successfully completed. +Any future events on the requested channel will be asynchronously sent +as `event` packets using the same tag as the subscribe request. + +### `_type: unsubscribed` + +Only one management client can be subscribed to any given event topic, so if +another subscribe request arrives, the older client will be sent this message +to let them know that they have been replaced. + +(In the future, this may also be sent as a reply to a explicit unsubscribe +request) + +### `_type: replacing` + +If a new subscription request will replace an existing one, this message is +sent to the new client to inform them that they have replaced an older +connection. + +### `_type: event` + +Asynchronous events will arrive with this message type, using the same tag as +the original subscribe request. Just like with the `row` packets, the non +metadata contents are entirely defined by the topic and the specific n2n +version. + +## Subscribe API + +A client can subscribe to events using a request with the type of "s". +Once a subscribe has been successfully completed, any events published +on that channel will be forwarded to the client. + +Only one management client can be subscribed to any given event topic, +with newer subscriptions replacing older ones. + +The special channel "debug" will receive copies of all events published. +Note that this is for debugging of events and the packets may not have +the same tag as the debug subscription. + ## Authentication Some API requests will make global changes to the running daemon and may diff --git a/include/n2n.h b/include/n2n.h index 9ca353a..5a44b3d 100644 --- a/include/n2n.h +++ b/include/n2n.h @@ -286,4 +286,6 @@ const char* compression_str (uint8_t cmpr); const char* transop_str (enum n2n_transform tr); void readFromMgmtSocket (n2n_edge_t *eee); + +void mgmt_event_post (enum n2n_event_topic topic, void *data); #endif /* _N2N_H_ */ diff --git a/include/n2n_define.h b/include/n2n_define.h index 451dacb..0226b2b 100644 --- a/include/n2n_define.h +++ b/include/n2n_define.h @@ -121,6 +121,11 @@ enum sn_purge {SN_PURGEABLE = 0, SN_UNPURGEABLE = 1}; #define N2N_EDGE_MGMT_PORT 5644 #define N2N_SN_MGMT_PORT 5645 +enum n2n_event_topic { + N2N_EVENT_DEBUG = 0, + N2N_EVENT_TEST = 1, +}; + #define N2N_MGMT_PASSWORD "n2n" /* default password for management port access (so far, json only) */ diff --git a/scripts/n2n-ctl b/scripts/n2n-ctl index 4e63eda..84b48cb 100755 --- a/scripts/n2n-ctl +++ b/scripts/n2n-ctl @@ -41,23 +41,37 @@ class JsonUDP(): def _rx(self, tagstr): """Wait for rx packets""" - # TODO: there are no timeouts with any of the recv calls - data, _ = self.sock.recvfrom(1024) - data = json.loads(data.decode('utf8')) + seen_begin = False + while not seen_begin: + # TODO: there are no timeouts with any of the recv calls + data, _ = self.sock.recvfrom(1024) + data = json.loads(data.decode('utf8')) - # TODO: We assume the first packet we get will be tagged for us - # and be either an "error" or a "begin" - assert(data['_tag'] == tagstr) + # TODO: We assume the first packet we get will be tagged for us + assert(data['_tag'] == tagstr) - if data['_type'] == 'error': - raise ValueError('Error: {}'.format(data['error'])) + if data['_type'] == 'error': + raise ValueError('Error: {}'.format(data['error'])) - assert(data['_type'] == 'begin') + if data['_type'] == 'replacing': + # a signal that we have evicted an earlier subscribe + continue - # Ideally, we would confirm that this is our "begin", but that - # would need the cmd passed into this method, and that would - # probably require parsing the cmdline passed to us :-( - # assert(data['cmd'] == cmd) + if data['_type'] == 'subscribe': + return True + + if data['_type'] == 'begin': + seen_begin = True + + # Ideally, we would confirm that this is our "begin", but that + # would need the cmd passed into this method, and that would + # probably require parsing the cmdline passed to us :-( + # assert(data['cmd'] == cmd) + + continue + + raise ValueError('Unknown data type {} from ' + 'edge'.format(data['_type'])) result = list() error = None @@ -105,6 +119,21 @@ class JsonUDP(): def write(self, cmdline): return self._call('w', cmdline) + def sub(self, cmdline): + return self._call('s', cmdline) + + def readevent(self): + self.sock.settimeout(3600) + + data, _ = self.sock.recvfrom(1024) + data = json.loads(data.decode('utf8')) + # assert(data['_tag'] == tagstr) + assert(data['_type'] == 'event') + + del data['_tag'] + del data['_type'] + return data + def str_table(rows, columns, orderby): """Given an array of dicts, do a simple table print""" @@ -203,8 +232,17 @@ def subcmd_default(rpc, args): cmdline = ' '.join([args.cmd] + args.args) if args.write: rows = rpc.write(cmdline) - else: + elif args.read: rows = rpc.read(cmdline) + elif args.sub: + if not rpc.sub(cmdline): + raise ValueError('Could not subscribe') + while True: + event = rpc.readevent() + # FIXME: violates layering.. + print(json.dumps(event, sort_keys=True, indent=4)) + else: + raise ValueError('Unknown request type') return json.dumps(rows, sort_keys=True, indent=4) @@ -228,6 +266,8 @@ def main(): group.add_argument('--write', action='store_true', help='Make a write request (only to non pretty' 'printed cmds)') + group.add_argument('--sub', action='store_true', + help='Make a subscribe request') ap.add_argument('cmd', action='store', help='Command to run (try "help" for list)') @@ -236,6 +276,9 @@ def main(): args = ap.parse_args() + if not args.read and not args.write and not args.sub: + args.read = True + if args.raw or (args.cmd not in subcmds): func = subcmd_default else: diff --git a/src/edge_management.c b/src/edge_management.c index 1aff29b..9e562e3 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -61,7 +61,7 @@ typedef struct mgmt_handler { * Event topic names are defined in this structure */ typedef struct mgmt_events { - int topic; // topic number define + enum n2n_event_topic topic; char *cmd; char *help; } mgmt_events_t; @@ -80,22 +80,26 @@ typedef struct mgmt_events { } \ } while(0) -static void send_reply (mgmt_req_t *req, strbuf_t *buf, size_t msg_len) { - // TODO: error handling - sendto(req->eee->udp_mgmt_sock, buf->str, msg_len, 0, +ssize_t send_reply (mgmt_req_t *req, strbuf_t *buf, size_t msg_len) { + // TODO: better error handling (counters?) + return sendto(req->eee->udp_mgmt_sock, buf->str, msg_len, 0, (struct sockaddr *) &req->sender_sock, sizeof(struct sockaddr_in)); } +size_t gen_json_1str (strbuf_t *buf, char *tag, char *_type, char *key, char *val) { + return snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"%s\"," + "\"%s\":\"%s\"}\n", + tag, + _type, + key, + val); +} + static void send_json_1str (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, char *val) { - size_t msg_len = snprintf(buf->str, buf->size, - "{" - "\"_tag\":\"%s\"," - "\"_type\":\"%s\"," - "\"%s\":\"%s\"}\n", - req->tag, - _type, - key, - val); + size_t msg_len = gen_json_1str(buf, req->tag, _type, key, val); send_reply(req, buf, msg_len); } @@ -112,8 +116,14 @@ static void send_json_1uint (mgmt_req_t *req, strbuf_t *buf, char *_type, char * send_reply(req, buf, msg_len); } -static void event_debug (mgmt_req_t *req, strbuf_t *buf) { - send_json_1str(req, buf, "event", "test", "test"); +size_t event_debug (strbuf_t *buf, char *tag, void *data) { + traceEvent(TRACE_DEBUG, "Unexpected call to event_debug"); + return 0; +} + +size_t event_test (strbuf_t *buf, char *tag, void *data) { + size_t msg_len = gen_json_1str(buf, tag, "event", "test", (char *)data); + return msg_len; } static void mgmt_error (mgmt_req_t *req, strbuf_t *buf, char *msg) { @@ -315,6 +325,12 @@ static void mgmt_packetstats (mgmt_req_t *req, strbuf_t *buf, char *argv0, char send_reply(req, buf, msg_len); } +static void mgmt_post_test (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { + + send_json_1str(req, buf, "row", "sending", "test"); + mgmt_event_post (N2N_EVENT_TEST, argv); +} + static void mgmt_unimplemented (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { mgmt_error(req, buf, "unimplemented"); @@ -334,25 +350,60 @@ static const mgmt_handler_t mgmt_handlers[] = { { .cmd = "supernodes", .help = "List current supernodes", .func = mgmt_supernodes}, { .cmd = "timestamps", .help = "Event timestamps", .func = mgmt_timestamps}, { .cmd = "packetstats", .help = "traffic counters", .func = mgmt_packetstats}, + { .cmd = "post.test", .help = "send a test event", .func = mgmt_post_test}, { .cmd = "help", .flags = FLAG_WROK, .help = "Show JSON commands", .func = mgmt_help}, { .cmd = "help.events", .help = "Show available Subscribe topics", .func = mgmt_help_events}, }; /* Current subscriber for each event topic */ static mgmt_req_t mgmt_event_subscribers[] = { - [0] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, + [N2N_EVENT_DEBUG] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, + [N2N_EVENT_TEST] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, }; /* Map topic number to function */ -static const void (*mgmt_events[])(mgmt_req_t *req, strbuf_t *buf) = { - [0] = event_debug, +static const size_t (*mgmt_events[])(strbuf_t *buf, char *tag, void *data) = { + [N2N_EVENT_DEBUG] = event_debug, + [N2N_EVENT_TEST] = event_test, }; /* Allow help and subscriptions to use topic name */ static const mgmt_events_t mgmt_event_names[] = { - { .cmd = "debug", .topic = 0, .help = "All events - for event debugging"}, + { .cmd = "debug", .topic = N2N_EVENT_DEBUG, .help = "All events - for event debugging"}, + { .cmd = "test", .topic = N2N_EVENT_TEST, .help = "Used only by post.test"}, }; +void mgmt_event_post (enum n2n_event_topic topic, void *data) { + mgmt_req_t *debug = &mgmt_event_subscribers[N2N_EVENT_DEBUG]; + mgmt_req_t *sub = &mgmt_event_subscribers[topic]; + + if( sub->type != N2N_MGMT_SUB && debug->type != N2N_MGMT_SUB) { + // If neither of this topic or the debug topic have a subscriber + // then we dont need to do any work + return; + } + + char buf_space[100]; + strbuf_t *buf; + STRBUF_INIT(buf, buf_space); + + char *tag; + if (sub->type == N2N_MGMT_SUB) { + tag = sub->tag; + } else { + tag = debug->tag; + } + + size_t msg_len = mgmt_events[topic](buf, tag, data); + + if (sub->type == N2N_MGMT_SUB) { + send_reply(sub, buf, msg_len); + } + if (debug->type == N2N_MGMT_SUB) { + send_reply(debug, buf, msg_len); + } +} + static void mgmt_help_events (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { size_t msg_len; @@ -364,11 +415,11 @@ static void mgmt_help_events (mgmt_req_t *req, strbuf_t *buf, char *argv0, char char host[40]; char serv[6]; - if(getnameinfo( - (struct sockaddr *)&sub->sender_sock, sizeof(sub->sender_sock), - host, sizeof(host), - serv, sizeof(serv), - NI_NUMERICHOST|NI_NUMERICSERV) != 0) { + if((sub->type != N2N_MGMT_SUB) || + getnameinfo((struct sockaddr *)&sub->sender_sock, sizeof(sub->sender_sock), + host, sizeof(host), + serv, sizeof(serv), + NI_NUMERICHOST|NI_NUMERICSERV) != 0) { host[0] = '?'; host[1] = 0; serv[0] = '?'; @@ -533,7 +584,23 @@ static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { } if(req->type == N2N_MGMT_SUB) { - mgmt_error(req, buf, "unimplemented"); + int handler; + lookup_handler(handler, mgmt_event_names, argv0); + if(handler == -1) { + mgmt_error(req, buf, "unknowntopic"); + return; + } + + int topic = mgmt_event_names[handler].topic; + if(mgmt_event_subscribers[topic].type == N2N_MGMT_SUB) { + send_json_1str(&mgmt_event_subscribers[topic], buf, + "unsubscribed", "topic", argv0); + send_json_1str(req, buf, "replacing", "topic", argv0); + } + + memcpy(&mgmt_event_subscribers[topic], req, sizeof(*req)); + + send_json_1str(req, buf, "subscribe", "topic", argv0); return; } From 860b27d97caaf2439c30fcb9d735ce9463324ae5 Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 5 Feb 2022 20:03:09 +0000 Subject: [PATCH 37/38] Add event publishing for adding and removing P2P peers --- include/n2n.h | 2 +- include/n2n_define.h | 6 ++++ src/edge_management.c | 66 ++++++++++++++++++++++++++++++++----------- src/edge_utils.c | 4 +++ src/n2n.c | 4 +++ 5 files changed, 65 insertions(+), 17 deletions(-) diff --git a/include/n2n.h b/include/n2n.h index 5a44b3d..3874609 100644 --- a/include/n2n.h +++ b/include/n2n.h @@ -287,5 +287,5 @@ const char* transop_str (enum n2n_transform tr); void readFromMgmtSocket (n2n_edge_t *eee); -void mgmt_event_post (enum n2n_event_topic topic, void *data); +void mgmt_event_post (enum n2n_event_topic topic, int data0, void *data1); #endif /* _N2N_H_ */ diff --git a/include/n2n_define.h b/include/n2n_define.h index 0226b2b..4c4da21 100644 --- a/include/n2n_define.h +++ b/include/n2n_define.h @@ -124,8 +124,14 @@ enum sn_purge {SN_PURGEABLE = 0, SN_UNPURGEABLE = 1}; enum n2n_event_topic { N2N_EVENT_DEBUG = 0, N2N_EVENT_TEST = 1, + N2N_EVENT_PEER = 2, }; +#define N2N_EVENT_PEER_PURGE 1 +#define N2N_EVENT_PEER_CLEAR 2 +#define N2N_EVENT_PEER_DEL_P2P 3 +#define N2N_EVENT_PEER_ADD_P2P 4 + #define N2N_MGMT_PASSWORD "n2n" /* default password for management port access (so far, json only) */ diff --git a/src/edge_management.c b/src/edge_management.c index 9e562e3..38fb430 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -98,34 +98,63 @@ size_t gen_json_1str (strbuf_t *buf, char *tag, char *_type, char *key, char *va val); } +size_t gen_json_1uint (strbuf_t *buf, char *tag, char *_type, char *key, unsigned int val) { + return snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"%s\"," + "\"%s\":%u}\n", + tag, + _type, + key, + val); +} + static void send_json_1str (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, char *val) { size_t msg_len = gen_json_1str(buf, req->tag, _type, key, val); send_reply(req, buf, msg_len); } static void send_json_1uint (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, unsigned int val) { - size_t msg_len = snprintf(buf->str, buf->size, - "{" - "\"_tag\":\"%s\"," - "\"_type\":\"%s\"," - "\"%s\":%u}\n", - req->tag, - _type, - key, - val); + size_t msg_len = gen_json_1uint(buf, req->tag, _type, key, val); send_reply(req, buf, msg_len); } -size_t event_debug (strbuf_t *buf, char *tag, void *data) { +size_t event_debug (strbuf_t *buf, char *tag, int data0, void *data1) { traceEvent(TRACE_DEBUG, "Unexpected call to event_debug"); return 0; } -size_t event_test (strbuf_t *buf, char *tag, void *data) { - size_t msg_len = gen_json_1str(buf, tag, "event", "test", (char *)data); +size_t event_test (strbuf_t *buf, char *tag, int data0, void *data1) { + size_t msg_len = gen_json_1str(buf, tag, "event", "test", (char *)data1); return msg_len; } +size_t event_peer (strbuf_t *buf, char *tag, int data0, void *data1) { + int action = data0; + struct peer_info *peer = (struct peer_info *)data1; + + macstr_t mac_buf; + n2n_sock_str_t sockbuf; + + /* + * Just the peer_info bits that are needed for lookup (maccaddr) or + * firewall and routing (sockaddr) + * If needed, other details can be fetched via the edges method call. + */ + return snprintf(buf->str, buf->size, + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"event\"," + "\"action\":%i," + "\"macaddr\":\"%s\"," + "\"sockaddr\":\"%s\"}\n", + tag, + action, + (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), + sock_to_cstr(sockbuf, &(peer->sock))); +} + static void mgmt_error (mgmt_req_t *req, strbuf_t *buf, char *msg) { send_json_1str(req, buf, "error", "error", msg); } @@ -328,7 +357,7 @@ static void mgmt_packetstats (mgmt_req_t *req, strbuf_t *buf, char *argv0, char static void mgmt_post_test (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { send_json_1str(req, buf, "row", "sending", "test"); - mgmt_event_post (N2N_EVENT_TEST, argv); + mgmt_event_post (N2N_EVENT_TEST, -1, argv); } static void mgmt_unimplemented (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { @@ -359,24 +388,29 @@ static const mgmt_handler_t mgmt_handlers[] = { static mgmt_req_t mgmt_event_subscribers[] = { [N2N_EVENT_DEBUG] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, [N2N_EVENT_TEST] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, + [N2N_EVENT_PEER] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, }; /* Map topic number to function */ -static const size_t (*mgmt_events[])(strbuf_t *buf, char *tag, void *data) = { +static const size_t (*mgmt_events[])(strbuf_t *buf, char *tag, int data0, void *data1) = { [N2N_EVENT_DEBUG] = event_debug, [N2N_EVENT_TEST] = event_test, + [N2N_EVENT_PEER] = event_peer, }; /* Allow help and subscriptions to use topic name */ static const mgmt_events_t mgmt_event_names[] = { { .cmd = "debug", .topic = N2N_EVENT_DEBUG, .help = "All events - for event debugging"}, { .cmd = "test", .topic = N2N_EVENT_TEST, .help = "Used only by post.test"}, + { .cmd = "peer", .topic = N2N_EVENT_PEER, .help = "Changes to peer list"}, }; -void mgmt_event_post (enum n2n_event_topic topic, void *data) { +void mgmt_event_post (enum n2n_event_topic topic, int data0, void *data1) { mgmt_req_t *debug = &mgmt_event_subscribers[N2N_EVENT_DEBUG]; mgmt_req_t *sub = &mgmt_event_subscribers[topic]; + traceEvent(TRACE_DEBUG, "post topic=%i data0=%i", topic, data0); + if( sub->type != N2N_MGMT_SUB && debug->type != N2N_MGMT_SUB) { // If neither of this topic or the debug topic have a subscriber // then we dont need to do any work @@ -394,7 +428,7 @@ void mgmt_event_post (enum n2n_event_topic topic, void *data) { tag = debug->tag; } - size_t msg_len = mgmt_events[topic](buf, tag, data); + size_t msg_len = mgmt_events[topic](buf, tag, data0, data1); if (sub->type == N2N_MGMT_SUB) { send_reply(sub, buf, msg_len); diff --git a/src/edge_utils.c b/src/edge_utils.c index 056ef64..fdc47ff 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -811,6 +811,7 @@ static void peer_set_p2p_confirmed (n2n_edge_t * eee, scan_tmp = find_peer_by_sock(peer, eee->known_peers); if(scan_tmp != NULL) { HASH_DEL(eee->known_peers, scan_tmp); + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan); free(scan); scan = scan_tmp; memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t)); @@ -828,6 +829,7 @@ static void peer_set_p2p_confirmed (n2n_edge_t * eee, HASH_ADD_PEER(eee->known_peers, scan); scan->last_p2p = now; + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_ADD_P2P,scan); traceEvent(TRACE_DEBUG, "p2p connection established: %s [%s]", macaddr_str(mac_buf, mac), @@ -994,6 +996,7 @@ static void check_known_peer_sock_change (n2n_edge_t *eee, sock_to_cstr(sockbuf2, peer)); /* The peer has changed public socket. It can no longer be assumed to be reachable. */ HASH_DEL(eee->known_peers, scan); + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan); free(scan); register_with_new_peer(eee, from_supernode, via_multicast, mac, dev_addr, dev_desc, peer); @@ -1880,6 +1883,7 @@ static int find_peer_destination (n2n_edge_t * eee, * since the peer address may have changed. */ traceEvent(TRACE_DEBUG, "refreshing idle known peer"); HASH_DEL(eee->known_peers, scan); + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan); free(scan); /* NOTE: registration will be performed upon the receival of the next response packet */ } else { diff --git a/src/n2n.c b/src/n2n.c index a879439..de62e10 100644 --- a/src/n2n.c +++ b/src/n2n.c @@ -636,6 +636,8 @@ size_t purge_peer_list (struct peer_info **peer_list, } } HASH_DEL(*peer_list, scan); + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_PURGE,scan); + /* FIXME: generates events for more than just p2p */ retval++; free(scan); } @@ -652,6 +654,8 @@ size_t clear_peer_list (struct peer_info ** peer_list) { HASH_ITER(hh, *peer_list, scan, tmp) { HASH_DEL(*peer_list, scan); + mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_CLEAR,scan); + /* FIXME: generates events for more than just p2p */ retval++; free(scan); } From 017f1cf60efa758fd640e6643d55dfb86eaa50fa Mon Sep 17 00:00:00 2001 From: Hamish Coleman Date: Sat, 5 Feb 2022 20:05:50 +0000 Subject: [PATCH 38/38] Address lint issues --- src/edge_management.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/edge_management.c b/src/edge_management.c index 38fb430..86898e5 100644 --- a/src/edge_management.c +++ b/src/edge_management.c @@ -83,7 +83,7 @@ typedef struct mgmt_events { ssize_t send_reply (mgmt_req_t *req, strbuf_t *buf, size_t msg_len) { // TODO: better error handling (counters?) return sendto(req->eee->udp_mgmt_sock, buf->str, msg_len, 0, - (struct sockaddr *) &req->sender_sock, sizeof(struct sockaddr_in)); + (struct sockaddr *) &req->sender_sock, sizeof(struct sockaddr_in)); } size_t gen_json_1str (strbuf_t *buf, char *tag, char *_type, char *key, char *val) { @@ -100,14 +100,14 @@ size_t gen_json_1str (strbuf_t *buf, char *tag, char *_type, char *key, char *va size_t gen_json_1uint (strbuf_t *buf, char *tag, char *_type, char *key, unsigned int val) { return snprintf(buf->str, buf->size, - "{" - "\"_tag\":\"%s\"," - "\"_type\":\"%s\"," - "\"%s\":%u}\n", - tag, - _type, - key, - val); + "{" + "\"_tag\":\"%s\"," + "\"_type\":\"%s\"," + "\"%s\":%u}\n", + tag, + _type, + key, + val); } static void send_json_1str (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, char *val) { @@ -357,7 +357,7 @@ static void mgmt_packetstats (mgmt_req_t *req, strbuf_t *buf, char *argv0, char static void mgmt_post_test (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { send_json_1str(req, buf, "row", "sending", "test"); - mgmt_event_post (N2N_EVENT_TEST, -1, argv); + mgmt_event_post(N2N_EVENT_TEST, -1, argv); } static void mgmt_unimplemented (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { @@ -422,7 +422,7 @@ void mgmt_event_post (enum n2n_event_topic topic, int data0, void *data1) { STRBUF_INIT(buf, buf_space); char *tag; - if (sub->type == N2N_MGMT_SUB) { + if(sub->type == N2N_MGMT_SUB) { tag = sub->tag; } else { tag = debug->tag; @@ -430,10 +430,10 @@ void mgmt_event_post (enum n2n_event_topic topic, int data0, void *data1) { size_t msg_len = mgmt_events[topic](buf, tag, data0, data1); - if (sub->type == N2N_MGMT_SUB) { + if(sub->type == N2N_MGMT_SUB) { send_reply(sub, buf, msg_len); } - if (debug->type == N2N_MGMT_SUB) { + if(debug->type == N2N_MGMT_SUB) { send_reply(debug, buf, msg_len); } } @@ -450,10 +450,10 @@ static void mgmt_help_events (mgmt_req_t *req, strbuf_t *buf, char *argv0, char char serv[6]; if((sub->type != N2N_MGMT_SUB) || - getnameinfo((struct sockaddr *)&sub->sender_sock, sizeof(sub->sender_sock), - host, sizeof(host), - serv, sizeof(serv), - NI_NUMERICHOST|NI_NUMERICSERV) != 0) { + getnameinfo((struct sockaddr *)&sub->sender_sock, sizeof(sub->sender_sock), + host, sizeof(host), + serv, sizeof(serv), + NI_NUMERICHOST|NI_NUMERICSERV) != 0) { host[0] = '?'; host[1] = 0; serv[0] = '?';