mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 16:41:11 +02:00
Merge pull request #947 from hamishcoleman/json_pubsub
Add JSON pubsub framework for edge
This commit is contained in:
commit
4b8aaa7f6e
14
.github/workflows/cmake.yml
vendored
14
.github/workflows/cmake.yml
vendored
|
@ -66,3 +66,17 @@ jobs:
|
||||||
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more
|
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more
|
||||||
# detail
|
# detail
|
||||||
run: ctest -C $BUILD_TYPE
|
run: ctest -C $BUILD_TYPE
|
||||||
|
|
||||||
|
- if: ${{ failure() }}
|
||||||
|
name: Upload test data
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: tests-out
|
||||||
|
path: tests
|
||||||
|
|
||||||
|
- if: ${{ failure() }}
|
||||||
|
name: Upload cmake test output
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: tests-out
|
||||||
|
path: build/Testing
|
||||||
|
|
24
.github/workflows/tests.yml
vendored
24
.github/workflows/tests.yml
vendored
|
@ -91,18 +91,18 @@ jobs:
|
||||||
./configure
|
./configure
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Run embedded tests
|
- name: Run embedded unit tests
|
||||||
run: make test
|
run: make test.units
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- if: ${{ always() }}
|
- if: ${{ failure() }}
|
||||||
name: Move test outputs to an arch specific location
|
name: Move test outputs to an arch specific location
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
mkdir -p tests/${{ matrix.os }}
|
mkdir -p tests/${{ matrix.os }}
|
||||||
mv tests/*.out tests/${{ matrix.os }}
|
mv tests/*.out tests/${{ matrix.os }}
|
||||||
|
|
||||||
- if: ${{ always() }}
|
- if: ${{ failure() }}
|
||||||
name: Upload tests output
|
name: Upload tests output
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
|
@ -162,18 +162,18 @@ jobs:
|
||||||
./configure
|
./configure
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Run embedded tests
|
- name: Run embedded unit tests
|
||||||
run: make test
|
run: make test.units
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- if: ${{ always() }}
|
- if: ${{ failure() }}
|
||||||
name: Move test outputs to an arch specific location
|
name: Move test outputs to an arch specific location
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
mkdir -p tests/${{ matrix.os }}
|
mkdir -p tests/${{ matrix.os }}
|
||||||
mv tests/*.out tests/${{ matrix.os }}
|
mv tests/*.out tests/${{ matrix.os }}
|
||||||
|
|
||||||
- if: ${{ always() }}
|
- if: ${{ failure() }}
|
||||||
name: Upload tests output
|
name: Upload tests output
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
|
@ -237,18 +237,18 @@ jobs:
|
||||||
./scripts/hack_fakeautoconf.sh
|
./scripts/hack_fakeautoconf.sh
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Run embedded tests
|
- name: Run embedded unit tests
|
||||||
run: make test
|
run: make test.units
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- if: ${{ always() }}
|
- if: ${{ failure() }}
|
||||||
name: Move test outputs to an arch specific location
|
name: Move test outputs to an arch specific location
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
mkdir -p tests/${{ matrix.os }}
|
mkdir -p tests/${{ matrix.os }}
|
||||||
mv tests/*.out tests/${{ matrix.os }}
|
mv tests/*.out tests/${{ matrix.os }}
|
||||||
|
|
||||||
- if: ${{ always() }}
|
- if: ${{ failure() }}
|
||||||
name: Upload tests output
|
name: Upload tests output
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -309,10 +309,21 @@ install(FILES ${PROJECT_BINARY_DIR}/doc/supernode.1.gz
|
||||||
DESTINATION /usr/share/man/man1)
|
DESTINATION /usr/share/man/man1)
|
||||||
install(FILES ${PROJECT_BINARY_DIR}/doc/n2n.7.gz
|
install(FILES ${PROJECT_BINARY_DIR}/doc/n2n.7.gz
|
||||||
DESTINATION /usr/share/man/man7)
|
DESTINATION /usr/share/man/man7)
|
||||||
|
endif(DEFINED UNIX)
|
||||||
|
|
||||||
|
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||||
|
|
||||||
# TODO:
|
# TODO:
|
||||||
# - Add the right dependancy so that the tests binaries get built first
|
# - Add the right dependancy so that the tests binaries get built first
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_test(tests ${PROJECT_SOURCE_DIR}/scripts/test_harness.sh ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/tests)
|
add_test(NAME unit
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E env
|
||||||
endif(DEFINED UNIX)
|
TOPDIR=${PROJECT_SOURCE_DIR} BINDIR=${PROJECT_BINARY_DIR}
|
||||||
|
${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_harness.sh ${PROJECT_SOURCE_DIR}/tests/tests_integration.list
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
35
Makefile.in
35
Makefile.in
|
@ -84,16 +84,30 @@ N2N_DEPS=$(wildcard include/*.h) $(wildcard src/*.c) Makefile
|
||||||
# As source files pass the linter, they can be added here (If all the source
|
# As source files pass the linter, they can be added here (If all the source
|
||||||
# is passing the linter tests, this can be refactored)
|
# is passing the linter tests, this can be refactored)
|
||||||
LINT_CCODE=\
|
LINT_CCODE=\
|
||||||
|
include/curve25519.h \
|
||||||
include/edge_utils_win32.h \
|
include/edge_utils_win32.h \
|
||||||
|
include/header_encryption.h \
|
||||||
|
include/hexdump.h \
|
||||||
include/n2n_define.h \
|
include/n2n_define.h \
|
||||||
|
include/n2n_wire.h \
|
||||||
|
include/network_traffic_filter.h \
|
||||||
include/pearson.h \
|
include/pearson.h \
|
||||||
|
include/random_numbers.h \
|
||||||
|
include/sn_selection.h \
|
||||||
include/speck.h \
|
include/speck.h \
|
||||||
|
include/tf.h \
|
||||||
|
src/edge_management.c \
|
||||||
src/edge_utils_win32.c \
|
src/edge_utils_win32.c \
|
||||||
src/example_edge_embed_quick_edge_init.c \
|
src/example_edge_embed_quick_edge_init.c \
|
||||||
src/header_encryption.c \
|
src/header_encryption.c \
|
||||||
|
src/sn_management.c \
|
||||||
src/sn_selection.c \
|
src/sn_selection.c \
|
||||||
src/transform_cc20.c \
|
src/transform_cc20.c \
|
||||||
|
src/transform_null.c \
|
||||||
|
src/tuntap_freebsd.c \
|
||||||
src/tuntap_linux.c \
|
src/tuntap_linux.c \
|
||||||
|
src/tuntap_netbsd.c \
|
||||||
|
src/tuntap_osx.c \
|
||||||
src/wire.c \
|
src/wire.c \
|
||||||
tools/tests-auth.c \
|
tools/tests-auth.c \
|
||||||
tools/tests-compress.c \
|
tools/tests-compress.c \
|
||||||
|
@ -146,9 +160,8 @@ SUBDIRS+=tools
|
||||||
COVERAGEDIR?=coverage
|
COVERAGEDIR?=coverage
|
||||||
|
|
||||||
.PHONY: $(SUBDIRS)
|
.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)
|
all: version $(APPS) $(DOCS) $(SUBDIRS)
|
||||||
|
|
||||||
# This allows breaking the build if the version.sh script discovers
|
# This allows breaking the build if the version.sh script discovers
|
||||||
|
@ -188,9 +201,16 @@ $(N2N_LIB): $(N2N_OBJS)
|
||||||
|
|
||||||
win32/n2n_win32.a: win32
|
win32/n2n_win32.a: win32
|
||||||
|
|
||||||
test: tools
|
.PHONY: test test.units test.integration
|
||||||
scripts/test_harness.sh
|
test: test.units test.integration
|
||||||
|
|
||||||
|
test.units: tools
|
||||||
|
scripts/test_harness.sh tests/tests_units.list
|
||||||
|
|
||||||
|
test.integration: $(APPS)
|
||||||
|
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
|
lint: lint.python lint.ccode lint.shell lint.yaml
|
||||||
|
|
||||||
lint.python:
|
lint.python:
|
||||||
|
@ -209,6 +229,7 @@ lint.yaml:
|
||||||
# CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="--coverage"
|
# CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="--coverage"
|
||||||
# and run the desired tests. Ensure that package gcovr is installed
|
# and run the desired tests. Ensure that package gcovr is installed
|
||||||
# and then run "make cover"
|
# and then run "make cover"
|
||||||
|
.PHONY: cover
|
||||||
cover:
|
cover:
|
||||||
mkdir -p $(COVERAGEDIR)
|
mkdir -p $(COVERAGEDIR)
|
||||||
gcovr -s --html --html-details --output=$(COVERAGEDIR)/index.html
|
gcovr -s --html --html-details --output=$(COVERAGEDIR)/index.html
|
||||||
|
@ -217,11 +238,13 @@ cover:
|
||||||
# Unfortunately, these end up in the wrong directory due to the
|
# Unfortunately, these end up in the wrong directory due to the
|
||||||
# makefile layout
|
# makefile layout
|
||||||
# The steps to use this are similar to the "make cover" above
|
# The steps to use this are similar to the "make cover" above
|
||||||
|
.PHONY: gcov
|
||||||
gcov:
|
gcov:
|
||||||
gcov $(N2N_OBJS)
|
gcov $(N2N_OBJS)
|
||||||
$(MAKE) -C tools gcov
|
$(MAKE) -C tools gcov
|
||||||
|
|
||||||
# This is a convinent target to use during development or from a CI/CD system
|
# This is a convinent target to use during development or from a CI/CD system
|
||||||
|
.PHONY: build-dep
|
||||||
build-dep:
|
build-dep:
|
||||||
ifeq ($(CONFIG_TARGET),generic)
|
ifeq ($(CONFIG_TARGET),generic)
|
||||||
sudo apt install $(BUILD_DEP)
|
sudo apt install $(BUILD_DEP)
|
||||||
|
@ -231,11 +254,13 @@ else
|
||||||
echo Not attempting to install dependancies for system $(CONFIG_TARGET)
|
echo Not attempting to install dependancies for system $(CONFIG_TARGET)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) $(COVERAGEDIR)/ *.dSYM *~
|
rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) $(COVERAGEDIR)/ *.dSYM *~
|
||||||
rm -f tests/*.out src/*.gcno src/*.gcda
|
rm -f tests/*.out src/*.gcno src/*.gcda
|
||||||
for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean; done
|
for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean; done
|
||||||
|
|
||||||
|
.PHONY: distclean
|
||||||
distclean:
|
distclean:
|
||||||
rm -f tests/*.out src/*.gcno src/*.gcda src/*.indent src/*.unc-backup*
|
rm -f tests/*.out src/*.gcno src/*.gcda src/*.indent src/*.unc-backup*
|
||||||
rm -rf autom4te.cache/
|
rm -rf autom4te.cache/
|
||||||
|
@ -246,6 +271,7 @@ distclean:
|
||||||
rm -f packages/rpm/config.log packages/rpm/config.status
|
rm -f packages/rpm/config.log packages/rpm/config.status
|
||||||
rm -f $(addprefix src/,$(APPS))
|
rm -f $(addprefix src/,$(APPS))
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
install: edge supernode edge.8.gz supernode.1.gz n2n.7.gz
|
install: edge supernode edge.8.gz supernode.1.gz n2n.7.gz
|
||||||
echo "MANDIR=$(MANDIR)"
|
echo "MANDIR=$(MANDIR)"
|
||||||
$(MKDIR) $(SBINDIR) $(MAN1DIR) $(MAN7DIR) $(MAN8DIR)
|
$(MKDIR) $(SBINDIR) $(MAN1DIR) $(MAN7DIR) $(MAN8DIR)
|
||||||
|
@ -261,6 +287,7 @@ DOCKER_IMAGE_NAME=ntop/supernode
|
||||||
DOCKER_IMAGE_VERSION=$N2N_VERSION_SHORT
|
DOCKER_IMAGE_VERSION=$N2N_VERSION_SHORT
|
||||||
N2N_COMMIT_HASH=$(shell scripts/version.sh hash)
|
N2N_COMMIT_HASH=$(shell scripts/version.sh hash)
|
||||||
|
|
||||||
|
.PHONY: default steps build push
|
||||||
default: steps
|
default: steps
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
|
@ -58,15 +58,23 @@ Fields:
|
||||||
|
|
||||||
The maximum length of the entire line of text is 80 octets.
|
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
|
### Message Type
|
||||||
|
|
||||||
This is a single octet that is either "r" for a read (or query) method
|
This is a single octet specifying the type:
|
||||||
call or "w" for a write (or change) method call.
|
|
||||||
|
- "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
|
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
|
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.
|
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
|
### Options
|
||||||
|
|
||||||
The options field is a colon separated set of options for this request. Only
|
The options field is a colon separated set of options for this request. Only
|
||||||
|
@ -83,14 +91,16 @@ SubFields:
|
||||||
|
|
||||||
Each request provides a tag value. Any non error reply associated with this
|
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
|
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
|
Where possible, the error replies will also include this tag, however some
|
||||||
errors occur before the tag is parsed.
|
errors occur before the tag is parsed.
|
||||||
|
|
||||||
The tag is not interpreted by the daemon, it is simply echoed back in all
|
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
|
the replies. It is expected to be a short string that the client knows
|
||||||
to be unique amongst all recent or still outstanding requests.
|
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
|
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.
|
for each request and wrapping around to zero when it is greater than 999.
|
||||||
|
@ -127,11 +137,14 @@ e.g:
|
||||||
Each UDP packet in the reply is a complete and valid JSON dictionary
|
Each UDP packet in the reply is a complete and valid JSON dictionary
|
||||||
containing a fragment of information related to the entire reply.
|
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
|
### Common metadata
|
||||||
|
|
||||||
There are two keys in each dictionary containing metadata. First
|
There are two keys in each dictionary containing metadata. First
|
||||||
is the `_tag`, containing the Message Tag from the original request.
|
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.
|
packet.
|
||||||
|
|
||||||
### `_type: error`
|
### `_type: error`
|
||||||
|
@ -176,6 +189,47 @@ packets will be required.
|
||||||
e.g:
|
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}`
|
`{"_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
|
## Authentication
|
||||||
|
|
||||||
Some API requests will make global changes to the running daemon and may
|
Some API requests will make global changes to the running daemon and may
|
||||||
|
|
|
@ -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
|
which checks or applies a set of rules to the code. It is used during
|
||||||
the automated lint checks.
|
the automated lint checks.
|
||||||
|
|
||||||
### `test_harness.sh`
|
|
||||||
|
|
||||||
This shell script is used to run automated tests during development.
|
|
||||||
|
|
||||||
### `n2n-gateway.sh`
|
### `n2n-gateway.sh`
|
||||||
|
|
||||||
A sample script to route all the host traffic towards a remote gateway,
|
A sample script to route all the host traffic towards a remote gateway,
|
||||||
|
@ -96,3 +92,26 @@ Manually test fetching and config:
|
||||||
/etc/munin/plugins/n2n_supernode_pkts
|
/etc/munin/plugins/n2n_supernode_pkts
|
||||||
/etc/munin/plugins/n2n_supernode_pkts config
|
/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 a testlist filename - pointing at a file containing the list of
|
||||||
|
tests to run.
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
Each test is a program, searched for in several locations, including the
|
||||||
|
`${listdir}/../scripts` dir.
|
||||||
|
|
||||||
|
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`
|
||||||
|
|
||||||
|
This starts a supernode and runs an integration test on the Json API using
|
||||||
|
the `n2n-ctl` command.
|
||||||
|
|
|
@ -285,6 +285,7 @@ int assign_one_ip_subnet (n2n_sn_t *sss, struct sn_community *comm);
|
||||||
const char* compression_str (uint8_t cmpr);
|
const char* compression_str (uint8_t cmpr);
|
||||||
const char* transop_str (enum n2n_transform tr);
|
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);
|
|
||||||
|
void mgmt_event_post (enum n2n_event_topic topic, int data0, void *data1);
|
||||||
#endif /* _N2N_H_ */
|
#endif /* _N2N_H_ */
|
||||||
|
|
|
@ -121,11 +121,17 @@ enum sn_purge {SN_PURGEABLE = 0, SN_UNPURGEABLE = 1};
|
||||||
#define N2N_EDGE_MGMT_PORT 5644
|
#define N2N_EDGE_MGMT_PORT 5644
|
||||||
#define N2N_SN_MGMT_PORT 5645
|
#define N2N_SN_MGMT_PORT 5645
|
||||||
|
|
||||||
enum n2n_mgmt_type {
|
enum n2n_event_topic {
|
||||||
N2N_MGMT_READ = 0,
|
N2N_EVENT_DEBUG = 0,
|
||||||
N2N_MGMT_WRITE = 1,
|
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) */
|
#define N2N_MGMT_PASSWORD "n2n" /* default password for management port access (so far, json only) */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ help() {
|
||||||
|
|
||||||
[ -z "$1" ] && help
|
[ -z "$1" ] && help
|
||||||
[ "$1" = "-h" ] && help
|
[ "$1" = "-h" ] && help
|
||||||
|
[ "$1" = "--help" ] && help
|
||||||
|
|
||||||
INPLACE=0
|
INPLACE=0
|
||||||
if [ "$1" = "-i" ]; then
|
if [ "$1" = "-i" ]; then
|
||||||
|
|
|
@ -41,24 +41,38 @@ class JsonUDP():
|
||||||
def _rx(self, tagstr):
|
def _rx(self, tagstr):
|
||||||
"""Wait for rx packets"""
|
"""Wait for rx packets"""
|
||||||
|
|
||||||
|
seen_begin = False
|
||||||
|
while not seen_begin:
|
||||||
# TODO: there are no timeouts with any of the recv calls
|
# TODO: there are no timeouts with any of the recv calls
|
||||||
data, _ = self.sock.recvfrom(1024)
|
data, _ = self.sock.recvfrom(1024)
|
||||||
data = json.loads(data.decode('utf8'))
|
data = json.loads(data.decode('utf8'))
|
||||||
|
|
||||||
# TODO: We assume the first packet we get will be tagged for us
|
# 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)
|
assert(data['_tag'] == tagstr)
|
||||||
|
|
||||||
if data['_type'] == 'error':
|
if data['_type'] == 'error':
|
||||||
raise ValueError('Error: {}'.format(data['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
|
||||||
|
|
||||||
|
if data['_type'] == 'subscribe':
|
||||||
|
return True
|
||||||
|
|
||||||
|
if data['_type'] == 'begin':
|
||||||
|
seen_begin = True
|
||||||
|
|
||||||
# Ideally, we would confirm that this is our "begin", but that
|
# Ideally, we would confirm that this is our "begin", but that
|
||||||
# would need the cmd passed into this method, and that would
|
# would need the cmd passed into this method, and that would
|
||||||
# probably require parsing the cmdline passed to us :-(
|
# probably require parsing the cmdline passed to us :-(
|
||||||
# assert(data['cmd'] == cmd)
|
# assert(data['cmd'] == cmd)
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise ValueError('Unknown data type {} from '
|
||||||
|
'edge'.format(data['_type']))
|
||||||
|
|
||||||
result = list()
|
result = list()
|
||||||
error = None
|
error = None
|
||||||
|
|
||||||
|
@ -105,6 +119,21 @@ class JsonUDP():
|
||||||
def write(self, cmdline):
|
def write(self, cmdline):
|
||||||
return self._call('w', 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):
|
def str_table(rows, columns, orderby):
|
||||||
"""Given an array of dicts, do a simple table print"""
|
"""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)
|
cmdline = ' '.join([args.cmd] + args.args)
|
||||||
if args.write:
|
if args.write:
|
||||||
rows = rpc.write(cmdline)
|
rows = rpc.write(cmdline)
|
||||||
else:
|
elif args.read:
|
||||||
rows = rpc.read(cmdline)
|
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)
|
return json.dumps(rows, sort_keys=True, indent=4)
|
||||||
|
|
||||||
|
|
||||||
|
@ -228,6 +266,8 @@ def main():
|
||||||
group.add_argument('--write', action='store_true',
|
group.add_argument('--write', action='store_true',
|
||||||
help='Make a write request (only to non pretty'
|
help='Make a write request (only to non pretty'
|
||||||
'printed cmds)')
|
'printed cmds)')
|
||||||
|
group.add_argument('--sub', action='store_true',
|
||||||
|
help='Make a subscribe request')
|
||||||
|
|
||||||
ap.add_argument('cmd', action='store',
|
ap.add_argument('cmd', action='store',
|
||||||
help='Command to run (try "help" for list)')
|
help='Command to run (try "help" for list)')
|
||||||
|
@ -236,6 +276,9 @@ def main():
|
||||||
|
|
||||||
args = ap.parse_args()
|
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):
|
if args.raw or (args.cmd not in subcmds):
|
||||||
func = subcmd_default
|
func = subcmd_default
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -23,102 +23,31 @@ import base64
|
||||||
|
|
||||||
from http import HTTPStatus
|
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):
|
def import_filename(modulename, filename):
|
||||||
self.address = "127.0.0.1"
|
# look in the same dir as this script
|
||||||
self.port = port
|
pathname = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||||
self.tag = 0
|
filename)
|
||||||
self.key = None
|
loader = importlib.machinery.SourceFileLoader(modulename, pathname)
|
||||||
self.debug = False
|
spec = importlib.util.spec_from_loader(modulename, loader)
|
||||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
module = importlib.util.module_from_spec(spec)
|
||||||
self.sock.settimeout(1)
|
|
||||||
|
|
||||||
def _next_tag(self):
|
try:
|
||||||
tagstr = str(self.tag)
|
loader.exec_module(module)
|
||||||
self.tag = (self.tag + 1) % 1000
|
except FileNotFoundError:
|
||||||
return tagstr
|
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]
|
# We share the implementation of the RPC class with the n2n-ctl script. We
|
||||||
if self.key is not None:
|
# cannot just import the module as 'n2n-ctl' has a dash in its name :-(
|
||||||
options += ['1'] # Flags set for auth key field
|
JsonUDP = import_filename('n2nctl', 'n2n-ctl').JsonUDP
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
pages = {
|
pages = {
|
||||||
|
|
|
@ -1,40 +1,47 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# This expects to find the tests in the tools dir and the expected results
|
# Run with the name of a test list file.
|
||||||
# in the tests dir.
|
#
|
||||||
|
# This expects to find the tests in the tools dir or scripts dir and the
|
||||||
|
# expected results in the tests dir.
|
||||||
|
|
||||||
TESTS="
|
# boilerplate so we can support whaky cmake dirs
|
||||||
tests-auth
|
[ -z "$TOPDIR" ] && TOPDIR="."
|
||||||
tests-compress
|
[ -z "$BINDIR" ] && BINDIR="."
|
||||||
tests-elliptic
|
export TOPDIR
|
||||||
tests-hashing
|
export BINDIR
|
||||||
tests-transform
|
|
||||||
tests-wire
|
|
||||||
"
|
|
||||||
|
|
||||||
TOOLSDIR=tools
|
if [ -z "$1" ]; then
|
||||||
TESTDATA=tests
|
echo need test list filename
|
||||||
|
|
||||||
# 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
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [ ! -e "$TESTDATA/$i.expected" ]; then
|
TESTLIST="$1"
|
||||||
echo "Could not find testdata $TESTDATA/$i.expected"
|
LISTDIR=$(dirname "$TESTLIST")
|
||||||
exit 1
|
|
||||||
fi
|
TESTS=$(sed -e "s/#.*//" "$TESTLIST")
|
||||||
done
|
|
||||||
|
|
||||||
# Actually run the tests
|
# Actually run the tests
|
||||||
set -e
|
|
||||||
for i in $TESTS; do
|
for i in $TESTS; do
|
||||||
echo "$TOOLSDIR/$i >$TESTDATA/$i.out"
|
# Look in several places for the test program
|
||||||
"$TOOLSDIR/$i" >"$TESTDATA/$i.out"
|
if [ -e "$BINDIR/$i" ]; then
|
||||||
cmp "$TESTDATA/$i.expected" "$TESTDATA/$i.out"
|
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
|
||||||
|
|
||||||
|
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" >"$LISTDIR/$i.out"
|
||||||
|
cmp "$LISTDIR/$i.expected" "$LISTDIR/$i.out"
|
||||||
|
set +e
|
||||||
done
|
done
|
||||||
|
|
49
scripts/test_integration_edge.sh
Executable file
49
scripts/test_integration_edge.sh
Executable file
|
@ -0,0 +1,49 @@
|
||||||
|
#!/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 --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
|
||||||
|
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
|
||||||
|
|
33
scripts/test_integration_supernode.sh
Executable file
33
scripts/test_integration_supernode.sh
Executable file
|
@ -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
|
||||||
|
|
|
@ -19,95 +19,184 @@
|
||||||
#include "n2n.h"
|
#include "n2n.h"
|
||||||
#include "edge_utils_win32.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,
|
||||||
|
N2N_MGMT_WRITE = 2,
|
||||||
|
N2N_MGMT_SUB = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Everything needed to reply to a request
|
||||||
|
*/
|
||||||
|
typedef struct mgmt_req {
|
||||||
|
n2n_edge_t *eee;
|
||||||
|
enum n2n_mgmt_type type;
|
||||||
|
char tag[10];
|
||||||
|
struct sockaddr_in sender_sock;
|
||||||
|
} mgmt_req_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read/Write handlers are defined in this structure
|
||||||
|
*/
|
||||||
#define FLAG_WROK 1
|
#define FLAG_WROK 1
|
||||||
typedef struct n2n_mgmt_handler {
|
typedef struct mgmt_handler {
|
||||||
int flags;
|
int flags;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
char *help;
|
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 *req, strbuf_t *buf, 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;
|
* Event topic names are defined in this structure
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
*/
|
||||||
|
typedef struct mgmt_events {
|
||||||
|
enum n2n_event_topic topic;
|
||||||
|
char *cmd;
|
||||||
|
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)
|
||||||
|
|
||||||
|
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\","
|
"\"_tag\":\"%s\","
|
||||||
"\"_type\":\"error\","
|
"\"_type\":\"%s\","
|
||||||
"\"error\":\"%s\"}\n",
|
"\"%s\":\"%s\"}\n",
|
||||||
tag,
|
tag,
|
||||||
msg);
|
_type,
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
key,
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
val);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
size_t gen_json_1uint (strbuf_t *buf, char *tag, char *_type, char *key, unsigned int val) {
|
||||||
size_t msg_len;
|
return snprintf(buf->str, buf->size,
|
||||||
|
|
||||||
if(type==N2N_MGMT_WRITE) {
|
|
||||||
*eee->keep_running = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
|
||||||
"{"
|
"{"
|
||||||
"\"_tag\":\"%s\","
|
"\"_tag\":\"%s\","
|
||||||
"\"_type\":\"row\","
|
"\"_type\":\"%s\","
|
||||||
"\"keep_running\":%u}\n",
|
"\"%s\":%u}\n",
|
||||||
tag,
|
tag,
|
||||||
*eee->keep_running);
|
_type,
|
||||||
|
key,
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
val);
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 send_json_1str (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, char *val) {
|
||||||
size_t msg_len;
|
size_t msg_len = gen_json_1str(buf, req->tag, _type, key, val);
|
||||||
|
send_reply(req, buf, msg_len);
|
||||||
|
}
|
||||||
|
|
||||||
if(type==N2N_MGMT_WRITE) {
|
static void send_json_1uint (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, unsigned int 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, int data0, void *data1) {
|
||||||
|
traceEvent(TRACE_DEBUG, "Unexpected call to event_debug");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, buf, "row", "keep_running", *req->eee->keep_running);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mgmt_verbose (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) {
|
||||||
|
|
||||||
|
if(req->type==N2N_MGMT_WRITE) {
|
||||||
if(argv) {
|
if(argv) {
|
||||||
setTraceLevel(strtoul(argv, NULL, 0));
|
setTraceLevel(strtoul(argv, NULL, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
send_json_1uint(req, buf, "row", "traceLevel", getTraceLevel());
|
||||||
"{"
|
|
||||||
"\"_tag\":\"%s\","
|
|
||||||
"\"_type\":\"row\","
|
|
||||||
"\"traceLevel\":%u}\n",
|
|
||||||
tag,
|
|
||||||
getTraceLevel());
|
|
||||||
|
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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, strbuf_t *buf, char *argv0, char *argv) {
|
||||||
size_t msg_len;
|
|
||||||
|
|
||||||
if(eee->conf.header_encryption != HEADER_ENCRYPTION_NONE) {
|
if(req->eee->conf.header_encryption != HEADER_ENCRYPTION_NONE) {
|
||||||
mgmt_error(eee, udp_buf, sender_sock, tag, "noaccess");
|
mgmt_error(req, buf, "noaccess");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
send_json_1str(req, buf, "row", "community", (char *)req->eee->conf.community_name);
|
||||||
"{"
|
|
||||||
"\"_tag\":\"%s\","
|
|
||||||
"\"_type\":\"row\","
|
|
||||||
"\"community\":\"%s\"}",
|
|
||||||
tag,
|
|
||||||
eee->conf.community_name);
|
|
||||||
|
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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, strbuf_t *buf, char *argv0, char *argv) {
|
||||||
size_t msg_len;
|
size_t msg_len;
|
||||||
struct peer_info *peer, *tmpPeer;
|
struct peer_info *peer, *tmpPeer;
|
||||||
macstr_t mac_buf;
|
macstr_t mac_buf;
|
||||||
n2n_sock_str_t sockbuf;
|
n2n_sock_str_t sockbuf;
|
||||||
selection_criterion_str_t sel_buf;
|
selection_criterion_str_t sel_buf;
|
||||||
|
|
||||||
HASH_ITER(hh, eee->conf.supernodes, peer, tmpPeer) {
|
HASH_ITER(hh, req->eee->conf.supernodes, peer, tmpPeer) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO:
|
* TODO:
|
||||||
|
@ -116,7 +205,7 @@ static void mgmt_supernodes (n2n_edge_t *eee, char *udp_buf, const struct sockad
|
||||||
* - do we care?
|
* - do we care?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
msg_len = snprintf(buf->str, buf->size,
|
||||||
"{"
|
"{"
|
||||||
"\"_tag\":\"%s\","
|
"\"_tag\":\"%s\","
|
||||||
"\"_type\":\"row\","
|
"\"_type\":\"row\","
|
||||||
|
@ -128,28 +217,27 @@ static void mgmt_supernodes (n2n_edge_t *eee, char *udp_buf, const struct sockad
|
||||||
"\"selection\":\"%s\","
|
"\"selection\":\"%s\","
|
||||||
"\"last_seen\":%li,"
|
"\"last_seen\":%li,"
|
||||||
"\"uptime\":%li}\n",
|
"\"uptime\":%li}\n",
|
||||||
tag,
|
req->tag,
|
||||||
peer->version,
|
peer->version,
|
||||||
peer->purgeable,
|
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),
|
is_null_mac(peer->mac_addr) ? "" : macaddr_str(mac_buf, peer->mac_addr),
|
||||||
sock_to_cstr(sockbuf, &(peer->sock)),
|
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->last_seen,
|
||||||
peer->uptime);
|
peer->uptime);
|
||||||
|
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
send_reply(req, buf, msg_len);
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, strbuf_t *buf, struct peer_info *peer, char *mode) {
|
||||||
size_t msg_len;
|
size_t msg_len;
|
||||||
macstr_t mac_buf;
|
macstr_t mac_buf;
|
||||||
n2n_sock_str_t sockbuf;
|
n2n_sock_str_t sockbuf;
|
||||||
dec_ip_bit_str_t ip_bit_str = {'\0'};
|
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\","
|
"\"_tag\":\"%s\","
|
||||||
"\"_type\":\"row\","
|
"\"_type\":\"row\","
|
||||||
|
@ -163,7 +251,7 @@ static void mgmt_edges_row (n2n_edge_t *eee, char *udp_buf, const struct sockadd
|
||||||
"\"last_p2p\":%li,\n"
|
"\"last_p2p\":%li,\n"
|
||||||
"\"last_sent_query\":%li,\n"
|
"\"last_sent_query\":%li,\n"
|
||||||
"\"last_seen\":%li}\n",
|
"\"last_seen\":%li}\n",
|
||||||
tag,
|
req->tag,
|
||||||
mode,
|
mode,
|
||||||
(peer->dev_addr.net_addr == 0) ? "" : ip_subnet_to_str(ip_bit_str, &peer->dev_addr),
|
(peer->dev_addr.net_addr == 0) ? "" : ip_subnet_to_str(ip_bit_str, &peer->dev_addr),
|
||||||
peer->purgeable,
|
peer->purgeable,
|
||||||
|
@ -175,111 +263,113 @@ static void mgmt_edges_row (n2n_edge_t *eee, char *udp_buf, const struct sockadd
|
||||||
peer->last_sent_query,
|
peer->last_sent_query,
|
||||||
peer->last_seen);
|
peer->last_seen);
|
||||||
|
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/,
|
send_reply(req, buf, msg_len);
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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, strbuf_t *buf, char *argv0, char *argv) {
|
||||||
struct peer_info *peer, *tmpPeer;
|
struct peer_info *peer, *tmpPeer;
|
||||||
|
|
||||||
// dump nodes with forwarding through supernodes
|
// dump nodes with forwarding through supernodes
|
||||||
HASH_ITER(hh, eee->pending_peers, peer, tmpPeer) {
|
HASH_ITER(hh, req->eee->pending_peers, peer, tmpPeer) {
|
||||||
mgmt_edges_row(eee, udp_buf, sender_sock, tag, peer, "pSp");
|
mgmt_edges_row(req, buf, peer, "pSp");
|
||||||
}
|
}
|
||||||
|
|
||||||
// dump peer-to-peer nodes
|
// dump peer-to-peer nodes
|
||||||
HASH_ITER(hh, eee->known_peers, peer, tmpPeer) {
|
HASH_ITER(hh, req->eee->known_peers, peer, tmpPeer) {
|
||||||
mgmt_edges_row(eee, udp_buf, sender_sock, tag, peer, "p2p");
|
mgmt_edges_row(req, 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, strbuf_t *buf, char *argv0, char *argv) {
|
||||||
size_t msg_len;
|
size_t msg_len;
|
||||||
|
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
msg_len = snprintf(buf->str, buf->size,
|
||||||
"{"
|
"{"
|
||||||
"\"_tag\":\"%s\","
|
"\"_tag\":\"%s\","
|
||||||
"\"_type\":\"row\","
|
"\"_type\":\"row\","
|
||||||
"\"start_time\":%lu,"
|
"\"start_time\":%lu,"
|
||||||
"\"last_super\":%ld,"
|
"\"last_super\":%ld,"
|
||||||
"\"last_p2p\":%ld}\n",
|
"\"last_p2p\":%ld}\n",
|
||||||
tag,
|
req->tag,
|
||||||
eee->start_time,
|
req->eee->start_time,
|
||||||
eee->last_sup,
|
req->eee->last_sup,
|
||||||
eee->last_p2p);
|
req->eee->last_p2p);
|
||||||
|
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
send_reply(req, buf, msg_len);
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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, strbuf_t *buf, char *argv0, char *argv) {
|
||||||
size_t msg_len;
|
size_t msg_len;
|
||||||
|
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
msg_len = snprintf(buf->str, buf->size,
|
||||||
"{"
|
"{"
|
||||||
"\"_tag\":\"%s\","
|
"\"_tag\":\"%s\","
|
||||||
"\"_type\":\"row\","
|
"\"_type\":\"row\","
|
||||||
"\"type\":\"transop\","
|
"\"type\":\"transop\","
|
||||||
"\"tx_pkt\":%lu,"
|
"\"tx_pkt\":%lu,"
|
||||||
"\"rx_pkt\":%lu}\n",
|
"\"rx_pkt\":%lu}\n",
|
||||||
tag,
|
req->tag,
|
||||||
eee->transop.tx_cnt,
|
req->eee->transop.tx_cnt,
|
||||||
eee->transop.rx_cnt);
|
req->eee->transop.rx_cnt);
|
||||||
|
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
send_reply(req, buf, msg_len);
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
|
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
msg_len = snprintf(buf->str, buf->size,
|
||||||
"{"
|
"{"
|
||||||
"\"_tag\":\"%s\","
|
"\"_tag\":\"%s\","
|
||||||
"\"_type\":\"row\","
|
"\"_type\":\"row\","
|
||||||
"\"type\":\"p2p\","
|
"\"type\":\"p2p\","
|
||||||
"\"tx_pkt\":%u,"
|
"\"tx_pkt\":%u,"
|
||||||
"\"rx_pkt\":%u}\n",
|
"\"rx_pkt\":%u}\n",
|
||||||
tag,
|
req->tag,
|
||||||
eee->stats.tx_p2p,
|
req->eee->stats.tx_p2p,
|
||||||
eee->stats.rx_p2p);
|
req->eee->stats.rx_p2p);
|
||||||
|
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
send_reply(req, buf, msg_len);
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
|
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
msg_len = snprintf(buf->str, buf->size,
|
||||||
"{"
|
"{"
|
||||||
"\"_tag\":\"%s\","
|
"\"_tag\":\"%s\","
|
||||||
"\"_type\":\"row\","
|
"\"_type\":\"row\","
|
||||||
"\"type\":\"super\","
|
"\"type\":\"super\","
|
||||||
"\"tx_pkt\":%u,"
|
"\"tx_pkt\":%u,"
|
||||||
"\"rx_pkt\":%u}\n",
|
"\"rx_pkt\":%u}\n",
|
||||||
tag,
|
req->tag,
|
||||||
eee->stats.tx_sup,
|
req->eee->stats.tx_sup,
|
||||||
eee->stats.rx_sup);
|
req->eee->stats.rx_sup);
|
||||||
|
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
send_reply(req, buf, msg_len);
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
|
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
msg_len = snprintf(buf->str, buf->size,
|
||||||
"{"
|
"{"
|
||||||
"\"_tag\":\"%s\","
|
"\"_tag\":\"%s\","
|
||||||
"\"_type\":\"row\","
|
"\"_type\":\"row\","
|
||||||
"\"type\":\"super_broadcast\","
|
"\"type\":\"super_broadcast\","
|
||||||
"\"tx_pkt\":%u,"
|
"\"tx_pkt\":%u,"
|
||||||
"\"rx_pkt\":%u}\n",
|
"\"rx_pkt\":%u}\n",
|
||||||
tag,
|
req->tag,
|
||||||
eee->stats.tx_sup_broadcast,
|
req->eee->stats.tx_sup_broadcast,
|
||||||
eee->stats.rx_sup_broadcast);
|
req->eee->stats.rx_sup_broadcast);
|
||||||
|
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
send_reply(req, buf, msg_len);
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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_post_test (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) {
|
||||||
|
|
||||||
mgmt_error(eee, udp_buf, sender_sock, tag, "unimplemented");
|
send_json_1str(req, buf, "row", "sending", "test");
|
||||||
|
mgmt_event_post(N2N_EVENT_TEST, -1, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
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_unimplemented (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) {
|
||||||
|
|
||||||
n2n_mgmt_handler_t mgmt_handlers[] = {
|
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, 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},
|
{ .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},
|
{ .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop},
|
||||||
|
@ -289,32 +379,129 @@ n2n_mgmt_handler_t mgmt_handlers[] = {
|
||||||
{ .cmd = "supernodes", .help = "List current supernodes", .func = mgmt_supernodes},
|
{ .cmd = "supernodes", .help = "List current supernodes", .func = mgmt_supernodes},
|
||||||
{ .cmd = "timestamps", .help = "Event timestamps", .func = mgmt_timestamps},
|
{ .cmd = "timestamps", .help = "Event timestamps", .func = mgmt_timestamps},
|
||||||
{ .cmd = "packetstats", .help = "traffic counters", .func = mgmt_packetstats},
|
{ .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", .flags = FLAG_WROK, .help = "Show JSON commands", .func = mgmt_help},
|
||||||
{ .cmd = NULL },
|
{ .cmd = "help.events", .help = "Show available Subscribe topics", .func = mgmt_help_events},
|
||||||
};
|
};
|
||||||
|
|
||||||
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) {
|
/* Current subscriber for each event topic */
|
||||||
|
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, 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, 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
|
||||||
|
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, data0, data1);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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];
|
||||||
|
char host[40];
|
||||||
|
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) {
|
||||||
|
host[0] = '?';
|
||||||
|
host[1] = 0;
|
||||||
|
serv[0] = '?';
|
||||||
|
serv[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle a topic with no subscribers more cleanly
|
||||||
|
|
||||||
|
msg_len = snprintf(buf->str, buf->size,
|
||||||
|
"{"
|
||||||
|
"\"_tag\":\"%s\","
|
||||||
|
"\"_type\":\"row\","
|
||||||
|
"\"topic\":\"%s\","
|
||||||
|
"\"tag\":\"%s\","
|
||||||
|
"\"sockaddr\":\"%s:%s\","
|
||||||
|
"\"help\":\"%s\"}\n",
|
||||||
|
req->tag,
|
||||||
|
mgmt_event_names[i].cmd,
|
||||||
|
sub->tag,
|
||||||
|
host, serv,
|
||||||
|
mgmt_event_names[i].help);
|
||||||
|
|
||||||
|
send_reply(req, buf, msg_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mgmt_help (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) {
|
||||||
size_t msg_len;
|
size_t msg_len;
|
||||||
n2n_mgmt_handler_t *handler;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Even though this command is readonly, we deliberately do not check
|
* Even though this command is readonly, we deliberately do not check
|
||||||
* the type - allowing help replies to both read and write requests
|
* the type - allowing help replies to both read and write requests
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for( handler=mgmt_handlers; handler->cmd; handler++ ) {
|
int i;
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
int nr_handlers = sizeof(mgmt_handlers) / sizeof(mgmt_handler_t);
|
||||||
|
for( i=0; i < nr_handlers; i++ ) {
|
||||||
|
msg_len = snprintf(buf->str, buf->size,
|
||||||
"{"
|
"{"
|
||||||
"\"_tag\":\"%s\","
|
"\"_tag\":\"%s\","
|
||||||
"\"_type\":\"row\","
|
"\"_type\":\"row\","
|
||||||
"\"cmd\":\"%s\","
|
"\"cmd\":\"%s\","
|
||||||
"\"help\":\"%s\"}\n",
|
"\"help\":\"%s\"}\n",
|
||||||
tag,
|
req->tag,
|
||||||
handler->cmd,
|
mgmt_handlers[i].cmd,
|
||||||
handler->help);
|
mgmt_handlers[i].help);
|
||||||
|
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
send_reply(req, buf, msg_len);
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,37 +512,39 @@ static void mgmt_help (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in
|
||||||
* Reads are not dangerous, so they are simply allowed
|
* Reads are not dangerous, so they are simply allowed
|
||||||
* Writes are possibly dangerous, so they need a fake password
|
* 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(auth) {
|
||||||
/* If we have an auth key, it must match */
|
/* 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 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* if we dont have an auth key, we can still read */
|
/* 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 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
|
||||||
|
strbuf_t *buf;
|
||||||
char cmdlinebuf[80];
|
char cmdlinebuf[80];
|
||||||
enum n2n_mgmt_type type;
|
|
||||||
char *typechar;
|
char *typechar;
|
||||||
char *options;
|
char *options;
|
||||||
char *argv0;
|
char *argv0;
|
||||||
char *argv;
|
char *argv;
|
||||||
char *tag;
|
|
||||||
char *flagstr;
|
char *flagstr;
|
||||||
int flags;
|
int flags;
|
||||||
char *auth;
|
char *auth;
|
||||||
n2n_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 */
|
/* save a copy of the commandline before we reuse the udp_buf */
|
||||||
strncpy(cmdlinebuf, udp_buf, sizeof(cmdlinebuf)-1);
|
strncpy(cmdlinebuf, udp_buf, sizeof(cmdlinebuf)-1);
|
||||||
|
@ -363,32 +552,36 @@ void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in se
|
||||||
|
|
||||||
traceEvent(TRACE_DEBUG, "mgmt json %s", cmdlinebuf);
|
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");
|
typechar = strtok(cmdlinebuf, " \r\n");
|
||||||
if(!typechar) {
|
if(!typechar) {
|
||||||
/* should not happen */
|
/* should not happen */
|
||||||
mgmt_error(eee, udp_buf, sender_sock, "-1", "notype");
|
mgmt_error(req, buf, "notype");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(*typechar == 'r') {
|
if(*typechar == 'r') {
|
||||||
type=N2N_MGMT_READ;
|
req->type=N2N_MGMT_READ;
|
||||||
} else if(*typechar == 'w') {
|
} else if(*typechar == 'w') {
|
||||||
type=N2N_MGMT_WRITE;
|
req->type=N2N_MGMT_WRITE;
|
||||||
|
} else if(*typechar == 's') {
|
||||||
|
req->type=N2N_MGMT_SUB;
|
||||||
} else {
|
} else {
|
||||||
/* dunno how we got here */
|
mgmt_error(req, buf, "badtype");
|
||||||
mgmt_error(eee, udp_buf, sender_sock, "-1", "badtype");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract the tag to use in all reply packets */
|
/* Extract the tag to use in all reply packets */
|
||||||
options = strtok(NULL, " \r\n");
|
options = strtok(NULL, " \r\n");
|
||||||
if(!options) {
|
if(!options) {
|
||||||
mgmt_error(eee, udp_buf, sender_sock, "-1", "nooptions");
|
mgmt_error(req, buf, "nooptions");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
argv0 = strtok(NULL, " \r\n");
|
argv0 = strtok(NULL, " \r\n");
|
||||||
if(!argv0) {
|
if(!argv0) {
|
||||||
mgmt_error(eee, udp_buf, sender_sock, "-1", "nocmd");
|
mgmt_error(req, buf, "nocmd");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +594,10 @@ void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in se
|
||||||
/*
|
/*
|
||||||
* There might be an auth token mixed in with the tag
|
* There might be an auth token mixed in with the tag
|
||||||
*/
|
*/
|
||||||
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, ":");
|
flagstr = strtok(NULL, ":");
|
||||||
if(flagstr) {
|
if(flagstr) {
|
||||||
flags = strtoul(flagstr, NULL, 16);
|
flags = strtoul(flagstr, NULL, 16);
|
||||||
|
@ -416,23 +612,41 @@ void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in se
|
||||||
auth = NULL;
|
auth = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!mgmt_auth(eee, sender_sock, type, auth, argv0, argv)) {
|
if(!mgmt_auth(req, auth, argv0, argv)) {
|
||||||
mgmt_error(eee, udp_buf, sender_sock, tag, "badauth");
|
mgmt_error(req, buf, "badauth");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for( handler=mgmt_handlers; handler->cmd; handler++ ) {
|
if(req->type == N2N_MGMT_SUB) {
|
||||||
if(0 == strcmp(handler->cmd, argv0)) {
|
int handler;
|
||||||
break;
|
lookup_handler(handler, mgmt_event_names, argv0);
|
||||||
}
|
if(handler == -1) {
|
||||||
}
|
mgmt_error(req, buf, "unknowntopic");
|
||||||
if(!handler->cmd) {
|
|
||||||
mgmt_error(eee, udp_buf, sender_sock, tag, "unknowncmd");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((type==N2N_MGMT_WRITE) && !(handler->flags & FLAG_WROK)) {
|
int topic = mgmt_event_names[handler].topic;
|
||||||
mgmt_error(eee, udp_buf, sender_sock, tag, "readonly");
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int handler;
|
||||||
|
lookup_handler(handler, mgmt_handlers, argv0);
|
||||||
|
if(handler == -1) {
|
||||||
|
mgmt_error(req, buf, "unknowncmd");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((req->type==N2N_MGMT_WRITE) && !(mgmt_handlers[handler].flags & FLAG_WROK)) {
|
||||||
|
mgmt_error(req, buf, "readonly");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,16 +656,243 @@ void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in se
|
||||||
* that make our JSON invalid.
|
* that make our JSON invalid.
|
||||||
* - do we care?
|
* - do we care?
|
||||||
*/
|
*/
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
send_json_1str(req, buf, "begin", "cmd", argv0);
|
||||||
"{\"_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));
|
|
||||||
|
|
||||||
handler->func(eee, udp_buf, sender_sock, type, tag, argv0, argv);
|
mgmt_handlers[handler].func(req, buf, argv0, argv);
|
||||||
|
|
||||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
send_json_1str(req, buf, "end", "cmd", argv0);
|
||||||
"{\"_tag\":\"%s\",\"_type\":\"end\"}\n", tag);
|
|
||||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
|
||||||
return;
|
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; */
|
||||||
|
mgmt_req_t req;
|
||||||
|
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;
|
||||||
|
|
||||||
|
req.eee = eee;
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
i = sizeof(req.sender_sock);
|
||||||
|
recvlen = recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0 /*flags*/,
|
||||||
|
(struct sockaddr *) &req.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))) {
|
||||||
|
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<enter> | Display statistics\n\n");
|
||||||
|
|
||||||
|
send_reply(&req, buf, msg_len);
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
setTraceLevel(getTraceLevel() + 1);
|
||||||
|
|
||||||
|
traceEvent(TRACE_NORMAL, "+verb traceLevel=%u", (unsigned int) getTraceLevel());
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
strbuf_t *buf;
|
||||||
|
STRBUF_INIT(buf, &udp_buf);
|
||||||
|
|
||||||
|
if(getTraceLevel() > 0) {
|
||||||
|
setTraceLevel(getTraceLevel() - 1);
|
||||||
|
msg_len = snprintf(buf->str, buf->size,
|
||||||
|
"> -OK traceLevel=%u\n", getTraceLevel());
|
||||||
|
} else {
|
||||||
|
msg_len = snprintf(buf->str, buf->size,
|
||||||
|
"> -NOK traceLevel=%u\n", getTraceLevel());
|
||||||
|
}
|
||||||
|
|
||||||
|
traceEvent(TRACE_NORMAL, "-verb traceLevel=%u", (unsigned int) getTraceLevel());
|
||||||
|
|
||||||
|
send_reply(&req, buf, msg_len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((udp_buf[0] >= 'a' && udp_buf[0] <= 'z') && (udp_buf[1] == ' ')) {
|
||||||
|
/* this is a JSON request */
|
||||||
|
handleMgmtJson(&req, udp_buf, recvlen);
|
||||||
|
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,
|
||||||
|
(struct sockaddr *) &req.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,
|
||||||
|
(struct sockaddr *) &req.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 *) &req.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");
|
||||||
|
|
||||||
|
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||||
|
(struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in));
|
||||||
|
}
|
||||||
|
|
236
src/edge_utils.c
236
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);
|
scan_tmp = find_peer_by_sock(peer, eee->known_peers);
|
||||||
if(scan_tmp != NULL) {
|
if(scan_tmp != NULL) {
|
||||||
HASH_DEL(eee->known_peers, scan_tmp);
|
HASH_DEL(eee->known_peers, scan_tmp);
|
||||||
|
mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan);
|
||||||
free(scan);
|
free(scan);
|
||||||
scan = scan_tmp;
|
scan = scan_tmp;
|
||||||
memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t));
|
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);
|
HASH_ADD_PEER(eee->known_peers, scan);
|
||||||
scan->last_p2p = now;
|
scan->last_p2p = now;
|
||||||
|
mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_ADD_P2P,scan);
|
||||||
|
|
||||||
traceEvent(TRACE_DEBUG, "p2p connection established: %s [%s]",
|
traceEvent(TRACE_DEBUG, "p2p connection established: %s [%s]",
|
||||||
macaddr_str(mac_buf, mac),
|
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));
|
sock_to_cstr(sockbuf2, peer));
|
||||||
/* The peer has changed public socket. It can no longer be assumed to be reachable. */
|
/* The peer has changed public socket. It can no longer be assumed to be reachable. */
|
||||||
HASH_DEL(eee->known_peers, scan);
|
HASH_DEL(eee->known_peers, scan);
|
||||||
|
mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan);
|
||||||
free(scan);
|
free(scan);
|
||||||
|
|
||||||
register_with_new_peer(eee, from_supernode, via_multicast, mac, dev_addr, dev_desc, peer);
|
register_with_new_peer(eee, from_supernode, via_multicast, mac, dev_addr, dev_desc, peer);
|
||||||
|
@ -1821,238 +1824,6 @@ static char *get_ip_from_arp (dec_ip_str_t buf, const n2n_mac_t req_mac) {
|
||||||
#endif
|
#endif
|
||||||
#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<enter> | 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) {
|
static int check_query_peer_info (n2n_edge_t *eee, time_t now, n2n_mac_t mac) {
|
||||||
|
@ -2112,6 +1883,7 @@ static int find_peer_destination (n2n_edge_t * eee,
|
||||||
* since the peer address may have changed. */
|
* since the peer address may have changed. */
|
||||||
traceEvent(TRACE_DEBUG, "refreshing idle known peer");
|
traceEvent(TRACE_DEBUG, "refreshing idle known peer");
|
||||||
HASH_DEL(eee->known_peers, scan);
|
HASH_DEL(eee->known_peers, scan);
|
||||||
|
mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan);
|
||||||
free(scan);
|
free(scan);
|
||||||
/* NOTE: registration will be performed upon the receival of the next response packet */
|
/* NOTE: registration will be performed upon the receival of the next response packet */
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -636,6 +636,8 @@ size_t purge_peer_list (struct peer_info **peer_list,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HASH_DEL(*peer_list, scan);
|
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++;
|
retval++;
|
||||||
free(scan);
|
free(scan);
|
||||||
}
|
}
|
||||||
|
@ -652,6 +654,8 @@ size_t clear_peer_list (struct peer_info ** peer_list) {
|
||||||
|
|
||||||
HASH_ITER(hh, *peer_list, scan, tmp) {
|
HASH_ITER(hh, *peer_list, scan, tmp) {
|
||||||
HASH_DEL(*peer_list, scan);
|
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++;
|
retval++;
|
||||||
free(scan);
|
free(scan);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,18 @@
|
||||||
|
|
||||||
int load_allowed_sn_community (n2n_sn_t *sss); /* defined in sn_utils.c */
|
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
|
#define FLAG_WROK 1
|
||||||
typedef struct n2n_mgmt_handler {
|
typedef struct mgmt_handler {
|
||||||
int flags;
|
int flags;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
char *help;
|
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);
|
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) {
|
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;
|
size_t msg_len;
|
||||||
|
@ -263,7 +268,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);
|
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 = "supernodes", .help = "Reserved for edge", .func = mgmt_unimplemented},
|
||||||
|
|
||||||
{ .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop},
|
{ .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop},
|
||||||
|
@ -279,7 +284,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) {
|
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;
|
size_t msg_len;
|
||||||
n2n_mgmt_handler_t *handler;
|
mgmt_handler_t *handler;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Even though this command is readonly, we deliberately do not check
|
* Even though this command is readonly, we deliberately do not check
|
||||||
|
@ -326,7 +331,7 @@ static int mgmt_auth (n2n_sn_t *sss, const struct sockaddr_in sender_sock, enum
|
||||||
return 0;
|
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];
|
char cmdlinebuf[80];
|
||||||
enum n2n_mgmt_type type;
|
enum n2n_mgmt_type type;
|
||||||
|
@ -338,7 +343,7 @@ void handleMgmtJson_sn (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in s
|
||||||
char *flagstr;
|
char *flagstr;
|
||||||
int flags;
|
int flags;
|
||||||
char *auth;
|
char *auth;
|
||||||
n2n_mgmt_handler_t *handler;
|
mgmt_handler_t *handler;
|
||||||
size_t msg_len;
|
size_t msg_len;
|
||||||
|
|
||||||
/* save a copy of the commandline before we reuse the udp_buf */
|
/* save a copy of the commandline before we reuse the udp_buf */
|
||||||
|
@ -439,3 +444,164 @@ void handleMgmtJson_sn (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in s
|
||||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||||
return;
|
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<enter> | 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;
|
||||||
|
}
|
||||||
|
|
171
src/sn_utils.c
171
src/sn_utils.c
|
@ -30,11 +30,6 @@ static ssize_t sendto_peer (n2n_sn_t *sss,
|
||||||
const uint8_t *pktbuf,
|
const uint8_t *pktbuf,
|
||||||
size_t pktsize);
|
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 uint16_t reg_lifetime (n2n_sn_t *sss);
|
||||||
|
|
||||||
static int update_edge (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* p_last_sort,
|
||||||
time_t now);
|
time_t now);
|
||||||
|
|
||||||
static int process_mgmt (n2n_sn_t *sss,
|
int process_mgmt (n2n_sn_t *sss,
|
||||||
const struct sockaddr_in *sender_sock,
|
const struct sockaddr_in *sender_sock,
|
||||||
char *mgmt_buf,
|
char *mgmt_buf,
|
||||||
size_t mgmt_size,
|
size_t mgmt_size,
|
||||||
|
@ -1507,170 +1502,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<enter> | 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.
|
/** Examine a datagram and determine what to do with it.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -639,10 +639,24 @@ int main (int argc, char * const argv[]) {
|
||||||
scan->socket_fd = sss_node.sock;
|
scan->socket_fd = sss_node.sock;
|
||||||
|
|
||||||
#ifndef WIN32
|
#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(((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.userid = sss_node.userid == 0 ? pw->pw_uid : 0;
|
||||||
sss_node.groupid = sss_node.groupid == 0 ? pw->pw_gid : 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)) {
|
if((sss_node.userid != 0) || (sss_node.groupid != 0)) {
|
||||||
traceEvent(TRACE_NORMAL, "dropping privileges to uid=%d, gid=%d",
|
traceEvent(TRACE_NORMAL, "dropping privileges to uid=%d, gid=%d",
|
||||||
(signed int)sss_node.userid, (signed int)sss_node.groupid);
|
(signed int)sss_node.userid, (signed int)sss_node.groupid);
|
||||||
|
@ -651,7 +665,6 @@ int main (int argc, char * const argv[]) {
|
||||||
if((setgid(sss_node.groupid) != 0)
|
if((setgid(sss_node.groupid) != 0)
|
||||||
|| (setuid(sss_node.userid) != 0)) {
|
|| (setuid(sss_node.userid) != 0)) {
|
||||||
traceEvent(TRACE_ERROR, "unable to drop privileges [%u/%s]", errno, strerror(errno));
|
traceEvent(TRACE_ERROR, "unable to drop privileges [%u/%s]", errno, strerror(errno));
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
74
tests/test_integration_edge.sh.expected
Normal file
74
tests/test_integration_edge.sh.expected
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
###
|
||||||
|
|
||||||
|
###
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
0
|
||||||
|
###
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"traceLevel": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
###
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"keep_running": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
###
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"keep_running": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
###
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"keep_running": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
64
tests/test_integration_supernode.sh.expected
Normal file
64
tests/test_integration_supernode.sh.expected
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
5
tests/tests_integration.list
Normal file
5
tests/tests_integration.list
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#
|
||||||
|
# The integration tests
|
||||||
|
|
||||||
|
test_integration_supernode.sh
|
||||||
|
test_integration_edge.sh
|
9
tests/tests_units.list
Normal file
9
tests/tests_units.list
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#
|
||||||
|
# The unit tests
|
||||||
|
|
||||||
|
tests-auth
|
||||||
|
tests-compress
|
||||||
|
tests-elliptic
|
||||||
|
tests-hashing
|
||||||
|
tests-transform
|
||||||
|
tests-wire
|
Loading…
Reference in New Issue
Block a user