mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 00:21: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
|
||||
# detail
|
||||
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
|
||||
shell: bash
|
||||
|
||||
- name: Run embedded tests
|
||||
run: make test
|
||||
- name: Run embedded unit tests
|
||||
run: make test.units
|
||||
shell: bash
|
||||
|
||||
- if: ${{ always() }}
|
||||
- if: ${{ failure() }}
|
||||
name: Move test outputs to an arch specific location
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p tests/${{ matrix.os }}
|
||||
mv tests/*.out tests/${{ matrix.os }}
|
||||
|
||||
- if: ${{ always() }}
|
||||
- if: ${{ failure() }}
|
||||
name: Upload tests output
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
@ -162,18 +162,18 @@ jobs:
|
|||
./configure
|
||||
shell: bash
|
||||
|
||||
- name: Run embedded tests
|
||||
run: make test
|
||||
- name: Run embedded unit tests
|
||||
run: make test.units
|
||||
shell: bash
|
||||
|
||||
- if: ${{ always() }}
|
||||
- if: ${{ failure() }}
|
||||
name: Move test outputs to an arch specific location
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p tests/${{ matrix.os }}
|
||||
mv tests/*.out tests/${{ matrix.os }}
|
||||
|
||||
- if: ${{ always() }}
|
||||
- if: ${{ failure() }}
|
||||
name: Upload tests output
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
@ -237,18 +237,18 @@ jobs:
|
|||
./scripts/hack_fakeautoconf.sh
|
||||
shell: bash
|
||||
|
||||
- name: Run embedded tests
|
||||
run: make test
|
||||
- name: Run embedded unit tests
|
||||
run: make test.units
|
||||
shell: bash
|
||||
|
||||
- if: ${{ always() }}
|
||||
- if: ${{ failure() }}
|
||||
name: Move test outputs to an arch specific location
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p tests/${{ matrix.os }}
|
||||
mv tests/*.out tests/${{ matrix.os }}
|
||||
|
||||
- if: ${{ always() }}
|
||||
- if: ${{ failure() }}
|
||||
name: Upload tests output
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
|
|
@ -309,10 +309,21 @@ install(FILES ${PROJECT_BINARY_DIR}/doc/supernode.1.gz
|
|||
DESTINATION /usr/share/man/man1)
|
||||
install(FILES ${PROJECT_BINARY_DIR}/doc/n2n.7.gz
|
||||
DESTINATION /usr/share/man/man7)
|
||||
endif(DEFINED UNIX)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||
|
||||
# TODO:
|
||||
# - Add the right dependancy so that the tests binaries get built first
|
||||
enable_testing()
|
||||
add_test(tests ${PROJECT_SOURCE_DIR}/scripts/test_harness.sh ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/tests)
|
||||
|
||||
endif(DEFINED UNIX)
|
||||
add_test(NAME unit
|
||||
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_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
|
||||
# is passing the linter tests, this can be refactored)
|
||||
LINT_CCODE=\
|
||||
include/curve25519.h \
|
||||
include/edge_utils_win32.h \
|
||||
include/header_encryption.h \
|
||||
include/hexdump.h \
|
||||
include/n2n_define.h \
|
||||
include/n2n_wire.h \
|
||||
include/network_traffic_filter.h \
|
||||
include/pearson.h \
|
||||
include/random_numbers.h \
|
||||
include/sn_selection.h \
|
||||
include/speck.h \
|
||||
include/tf.h \
|
||||
src/edge_management.c \
|
||||
src/edge_utils_win32.c \
|
||||
src/example_edge_embed_quick_edge_init.c \
|
||||
src/header_encryption.c \
|
||||
src/sn_management.c \
|
||||
src/sn_selection.c \
|
||||
src/transform_cc20.c \
|
||||
src/transform_null.c \
|
||||
src/tuntap_freebsd.c \
|
||||
src/tuntap_linux.c \
|
||||
src/tuntap_netbsd.c \
|
||||
src/tuntap_osx.c \
|
||||
src/wire.c \
|
||||
tools/tests-auth.c \
|
||||
tools/tests-compress.c \
|
||||
|
@ -146,9 +160,8 @@ SUBDIRS+=tools
|
|||
COVERAGEDIR?=coverage
|
||||
|
||||
.PHONY: $(SUBDIRS)
|
||||
.PHONY: steps build push all clean distclean install test cover gcov build-dep
|
||||
.PHONY: lint lint.python lint.ccode lint.shell lint.yaml
|
||||
|
||||
.PHONY: all
|
||||
all: version $(APPS) $(DOCS) $(SUBDIRS)
|
||||
|
||||
# This allows breaking the build if the version.sh script discovers
|
||||
|
@ -188,9 +201,16 @@ $(N2N_LIB): $(N2N_OBJS)
|
|||
|
||||
win32/n2n_win32.a: win32
|
||||
|
||||
test: tools
|
||||
scripts/test_harness.sh
|
||||
.PHONY: test test.units test.integration
|
||||
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.python:
|
||||
|
@ -209,6 +229,7 @@ lint.yaml:
|
|||
# CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="--coverage"
|
||||
# and run the desired tests. Ensure that package gcovr is installed
|
||||
# and then run "make cover"
|
||||
.PHONY: cover
|
||||
cover:
|
||||
mkdir -p $(COVERAGEDIR)
|
||||
gcovr -s --html --html-details --output=$(COVERAGEDIR)/index.html
|
||||
|
@ -217,11 +238,13 @@ cover:
|
|||
# Unfortunately, these end up in the wrong directory due to the
|
||||
# makefile layout
|
||||
# The steps to use this are similar to the "make cover" above
|
||||
.PHONY: gcov
|
||||
gcov:
|
||||
gcov $(N2N_OBJS)
|
||||
$(MAKE) -C tools gcov
|
||||
|
||||
# This is a convinent target to use during development or from a CI/CD system
|
||||
.PHONY: build-dep
|
||||
build-dep:
|
||||
ifeq ($(CONFIG_TARGET),generic)
|
||||
sudo apt install $(BUILD_DEP)
|
||||
|
@ -231,11 +254,13 @@ else
|
|||
echo Not attempting to install dependancies for system $(CONFIG_TARGET)
|
||||
endif
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) $(COVERAGEDIR)/ *.dSYM *~
|
||||
rm -f tests/*.out src/*.gcno src/*.gcda
|
||||
for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean; done
|
||||
|
||||
.PHONY: distclean
|
||||
distclean:
|
||||
rm -f tests/*.out src/*.gcno src/*.gcda src/*.indent src/*.unc-backup*
|
||||
rm -rf autom4te.cache/
|
||||
|
@ -246,6 +271,7 @@ distclean:
|
|||
rm -f packages/rpm/config.log packages/rpm/config.status
|
||||
rm -f $(addprefix src/,$(APPS))
|
||||
|
||||
.PHONY: install
|
||||
install: edge supernode edge.8.gz supernode.1.gz n2n.7.gz
|
||||
echo "MANDIR=$(MANDIR)"
|
||||
$(MKDIR) $(SBINDIR) $(MAN1DIR) $(MAN7DIR) $(MAN8DIR)
|
||||
|
@ -261,6 +287,7 @@ DOCKER_IMAGE_NAME=ntop/supernode
|
|||
DOCKER_IMAGE_VERSION=$N2N_VERSION_SHORT
|
||||
N2N_COMMIT_HASH=$(shell scripts/version.sh hash)
|
||||
|
||||
.PHONY: default steps build push
|
||||
default: steps
|
||||
|
||||
steps:
|
||||
|
|
|
@ -58,15 +58,23 @@ Fields:
|
|||
|
||||
The maximum length of the entire line of text is 80 octets.
|
||||
|
||||
All request packets should generate a reply. However, this reply may simply
|
||||
be an error.
|
||||
|
||||
### Message Type
|
||||
|
||||
This is a single octet that is either "r" for a read (or query) method
|
||||
call or "w" for a write (or change) method call.
|
||||
This is a single octet specifying the type:
|
||||
|
||||
- "r" for a read-only method (or one that does not need change permissions)
|
||||
- "w" for a write method (or one that makes changes)
|
||||
- "s" for a subscribe method to request this socket receive some events
|
||||
|
||||
To simplify the interface, the reply from both read and write calls to the
|
||||
same method is expected to contain the same data. In the case of a write
|
||||
call, the reply will contain the new state after making the requested change.
|
||||
|
||||
The subscribe and events message flow works with a different set of messages.
|
||||
|
||||
### Options
|
||||
|
||||
The options field is a colon separated set of options for this request. Only
|
||||
|
@ -83,14 +91,16 @@ SubFields:
|
|||
|
||||
Each request provides a tag value. Any non error reply associated with this
|
||||
request will include this tag value, allowing all related messages to be
|
||||
collected within the client.
|
||||
collected within the client. The tag will be truncated if needed by the
|
||||
daemon, but there will be at least 8 octets of space available.
|
||||
|
||||
Where possible, the error replies will also include this tag, however some
|
||||
errors occur before the tag is parsed.
|
||||
|
||||
The tag is not interpreted by the daemon, it is simply echoed back in all
|
||||
the replies. It is expected to be a short string that the client chooses
|
||||
to be unique amongst all recent or still outstanding requests.
|
||||
the replies. It is expected to be a short string that the client knows
|
||||
will be unique amongst all recent, still outstanding or subscription requests
|
||||
on a given socket.
|
||||
|
||||
One possible client implementation is a number between 0 and 999, incremented
|
||||
for each request and wrapping around to zero when it is greater than 999.
|
||||
|
@ -127,11 +137,14 @@ e.g:
|
|||
Each UDP packet in the reply is a complete and valid JSON dictionary
|
||||
containing a fragment of information related to the entire reply.
|
||||
|
||||
Reply packets are generated both in response to requests and whenever
|
||||
an event is published to a subscribed channel.
|
||||
|
||||
### Common metadata
|
||||
|
||||
There are two keys in each dictionary containing metadata. First
|
||||
is the `_tag`, containing the Message Tag from the original request.
|
||||
Second is the `_type` whic identifies the expected contents of this
|
||||
Second is the `_type` which identifies the expected contents of this
|
||||
packet.
|
||||
|
||||
### `_type: error`
|
||||
|
@ -176,6 +189,47 @@ packets will be required.
|
|||
e.g:
|
||||
`{"_tag":"108","_type":"row","mode":"p2p","ip4addr":"10.135.98.84","macaddr":"86:56:21:E4:AA:39","sockaddr":"192.168.7.191:41701","desc":"client4","lastseen":1584682200}`
|
||||
|
||||
### `_type: subscribed`
|
||||
|
||||
Signals that the subscription request has been successfully completed.
|
||||
Any future events on the requested channel will be asynchronously sent
|
||||
as `event` packets using the same tag as the subscribe request.
|
||||
|
||||
### `_type: unsubscribed`
|
||||
|
||||
Only one management client can be subscribed to any given event topic, so if
|
||||
another subscribe request arrives, the older client will be sent this message
|
||||
to let them know that they have been replaced.
|
||||
|
||||
(In the future, this may also be sent as a reply to a explicit unsubscribe
|
||||
request)
|
||||
|
||||
### `_type: replacing`
|
||||
|
||||
If a new subscription request will replace an existing one, this message is
|
||||
sent to the new client to inform them that they have replaced an older
|
||||
connection.
|
||||
|
||||
### `_type: event`
|
||||
|
||||
Asynchronous events will arrive with this message type, using the same tag as
|
||||
the original subscribe request. Just like with the `row` packets, the non
|
||||
metadata contents are entirely defined by the topic and the specific n2n
|
||||
version.
|
||||
|
||||
## Subscribe API
|
||||
|
||||
A client can subscribe to events using a request with the type of "s".
|
||||
Once a subscribe has been successfully completed, any events published
|
||||
on that channel will be forwarded to the client.
|
||||
|
||||
Only one management client can be subscribed to any given event topic,
|
||||
with newer subscriptions replacing older ones.
|
||||
|
||||
The special channel "debug" will receive copies of all events published.
|
||||
Note that this is for debugging of events and the packets may not have
|
||||
the same tag as the debug subscription.
|
||||
|
||||
## Authentication
|
||||
|
||||
Some API requests will make global changes to the running daemon and may
|
||||
|
|
|
@ -51,10 +51,6 @@ This shell script is a wrapper for the `uncrustify` C code style checker
|
|||
which checks or applies a set of rules to the code. It is used during
|
||||
the automated lint checks.
|
||||
|
||||
### `test_harness.sh`
|
||||
|
||||
This shell script is used to run automated tests during development.
|
||||
|
||||
### `n2n-gateway.sh`
|
||||
|
||||
A sample script to route all the host traffic towards a remote gateway,
|
||||
|
@ -96,3 +92,26 @@ Manually test fetching and config:
|
|||
/etc/munin/plugins/n2n_supernode_pkts
|
||||
/etc/munin/plugins/n2n_supernode_pkts config
|
||||
```
|
||||
|
||||
## Testing scripts
|
||||
|
||||
### `test_harness.sh`
|
||||
|
||||
This shell script is used to run automated tests during development. It is
|
||||
run with 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* transop_str (enum n2n_transform tr);
|
||||
|
||||
void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock);
|
||||
void handleMgmtJson_sn (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock);
|
||||
void readFromMgmtSocket (n2n_edge_t *eee);
|
||||
|
||||
void mgmt_event_post (enum n2n_event_topic topic, int data0, void *data1);
|
||||
#endif /* _N2N_H_ */
|
||||
|
|
|
@ -121,11 +121,17 @@ enum sn_purge {SN_PURGEABLE = 0, SN_UNPURGEABLE = 1};
|
|||
#define N2N_EDGE_MGMT_PORT 5644
|
||||
#define N2N_SN_MGMT_PORT 5645
|
||||
|
||||
enum n2n_mgmt_type {
|
||||
N2N_MGMT_READ = 0,
|
||||
N2N_MGMT_WRITE = 1,
|
||||
enum n2n_event_topic {
|
||||
N2N_EVENT_DEBUG = 0,
|
||||
N2N_EVENT_TEST = 1,
|
||||
N2N_EVENT_PEER = 2,
|
||||
};
|
||||
|
||||
#define N2N_EVENT_PEER_PURGE 1
|
||||
#define N2N_EVENT_PEER_CLEAR 2
|
||||
#define N2N_EVENT_PEER_DEL_P2P 3
|
||||
#define N2N_EVENT_PEER_ADD_P2P 4
|
||||
|
||||
#define N2N_MGMT_PASSWORD "n2n" /* default password for management port access (so far, json only) */
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ help() {
|
|||
|
||||
[ -z "$1" ] && help
|
||||
[ "$1" = "-h" ] && help
|
||||
[ "$1" = "--help" ] && help
|
||||
|
||||
INPLACE=0
|
||||
if [ "$1" = "-i" ]; then
|
||||
|
|
|
@ -41,23 +41,37 @@ class JsonUDP():
|
|||
def _rx(self, tagstr):
|
||||
"""Wait for rx packets"""
|
||||
|
||||
# TODO: there are no timeouts with any of the recv calls
|
||||
data, _ = self.sock.recvfrom(1024)
|
||||
data = json.loads(data.decode('utf8'))
|
||||
seen_begin = False
|
||||
while not seen_begin:
|
||||
# TODO: there are no timeouts with any of the recv calls
|
||||
data, _ = self.sock.recvfrom(1024)
|
||||
data = json.loads(data.decode('utf8'))
|
||||
|
||||
# TODO: We assume the first packet we get will be tagged for us
|
||||
# and be either an "error" or a "begin"
|
||||
assert(data['_tag'] == tagstr)
|
||||
# TODO: We assume the first packet we get will be tagged for us
|
||||
assert(data['_tag'] == tagstr)
|
||||
|
||||
if data['_type'] == 'error':
|
||||
raise ValueError('Error: {}'.format(data['error']))
|
||||
if data['_type'] == 'error':
|
||||
raise ValueError('Error: {}'.format(data['error']))
|
||||
|
||||
assert(data['_type'] == 'begin')
|
||||
if data['_type'] == 'replacing':
|
||||
# a signal that we have evicted an earlier subscribe
|
||||
continue
|
||||
|
||||
# Ideally, we would confirm that this is our "begin", but that
|
||||
# would need the cmd passed into this method, and that would
|
||||
# probably require parsing the cmdline passed to us :-(
|
||||
# assert(data['cmd'] == cmd)
|
||||
if data['_type'] == 'subscribe':
|
||||
return True
|
||||
|
||||
if data['_type'] == 'begin':
|
||||
seen_begin = True
|
||||
|
||||
# Ideally, we would confirm that this is our "begin", but that
|
||||
# would need the cmd passed into this method, and that would
|
||||
# probably require parsing the cmdline passed to us :-(
|
||||
# assert(data['cmd'] == cmd)
|
||||
|
||||
continue
|
||||
|
||||
raise ValueError('Unknown data type {} from '
|
||||
'edge'.format(data['_type']))
|
||||
|
||||
result = list()
|
||||
error = None
|
||||
|
@ -105,6 +119,21 @@ class JsonUDP():
|
|||
def write(self, cmdline):
|
||||
return self._call('w', cmdline)
|
||||
|
||||
def sub(self, cmdline):
|
||||
return self._call('s', cmdline)
|
||||
|
||||
def readevent(self):
|
||||
self.sock.settimeout(3600)
|
||||
|
||||
data, _ = self.sock.recvfrom(1024)
|
||||
data = json.loads(data.decode('utf8'))
|
||||
# assert(data['_tag'] == tagstr)
|
||||
assert(data['_type'] == 'event')
|
||||
|
||||
del data['_tag']
|
||||
del data['_type']
|
||||
return data
|
||||
|
||||
|
||||
def str_table(rows, columns, orderby):
|
||||
"""Given an array of dicts, do a simple table print"""
|
||||
|
@ -203,8 +232,17 @@ def subcmd_default(rpc, args):
|
|||
cmdline = ' '.join([args.cmd] + args.args)
|
||||
if args.write:
|
||||
rows = rpc.write(cmdline)
|
||||
else:
|
||||
elif args.read:
|
||||
rows = rpc.read(cmdline)
|
||||
elif args.sub:
|
||||
if not rpc.sub(cmdline):
|
||||
raise ValueError('Could not subscribe')
|
||||
while True:
|
||||
event = rpc.readevent()
|
||||
# FIXME: violates layering..
|
||||
print(json.dumps(event, sort_keys=True, indent=4))
|
||||
else:
|
||||
raise ValueError('Unknown request type')
|
||||
return json.dumps(rows, sort_keys=True, indent=4)
|
||||
|
||||
|
||||
|
@ -228,6 +266,8 @@ def main():
|
|||
group.add_argument('--write', action='store_true',
|
||||
help='Make a write request (only to non pretty'
|
||||
'printed cmds)')
|
||||
group.add_argument('--sub', action='store_true',
|
||||
help='Make a subscribe request')
|
||||
|
||||
ap.add_argument('cmd', action='store',
|
||||
help='Command to run (try "help" for list)')
|
||||
|
@ -236,6 +276,9 @@ def main():
|
|||
|
||||
args = ap.parse_args()
|
||||
|
||||
if not args.read and not args.write and not args.sub:
|
||||
args.read = True
|
||||
|
||||
if args.raw or (args.cmd not in subcmds):
|
||||
func = subcmd_default
|
||||
else:
|
||||
|
|
|
@ -23,102 +23,31 @@ import base64
|
|||
|
||||
from http import HTTPStatus
|
||||
|
||||
import os
|
||||
import sys
|
||||
import importlib.machinery
|
||||
import importlib.util
|
||||
|
||||
class JsonUDP():
|
||||
"""encapsulate communication with the edge"""
|
||||
|
||||
def __init__(self, port):
|
||||
self.address = "127.0.0.1"
|
||||
self.port = port
|
||||
self.tag = 0
|
||||
self.key = None
|
||||
self.debug = False
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
self.sock.settimeout(1)
|
||||
def import_filename(modulename, filename):
|
||||
# look in the same dir as this script
|
||||
pathname = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
filename)
|
||||
loader = importlib.machinery.SourceFileLoader(modulename, pathname)
|
||||
spec = importlib.util.spec_from_loader(modulename, loader)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
|
||||
def _next_tag(self):
|
||||
tagstr = str(self.tag)
|
||||
self.tag = (self.tag + 1) % 1000
|
||||
return tagstr
|
||||
try:
|
||||
loader.exec_module(module)
|
||||
except FileNotFoundError:
|
||||
print("Script {} not found".format(pathname), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
return module
|
||||
|
||||
def _cmdstr(self, msgtype, cmdline):
|
||||
"""Create the full command string to send"""
|
||||
tagstr = self._next_tag()
|
||||
|
||||
options = [tagstr]
|
||||
if self.key is not None:
|
||||
options += ['1'] # Flags set for auth key field
|
||||
options += [self.key]
|
||||
optionsstr = ':'.join(options)
|
||||
|
||||
return tagstr, ' '.join((msgtype, optionsstr, cmdline))
|
||||
|
||||
def _rx(self, tagstr):
|
||||
"""Wait for rx packets"""
|
||||
|
||||
# TODO: there are no timeouts with any of the recv calls
|
||||
data, _ = self.sock.recvfrom(1024)
|
||||
data = json.loads(data.decode('utf8'))
|
||||
|
||||
# TODO: We assume the first packet we get will be tagged for us
|
||||
# and be either an "error" or a "begin"
|
||||
assert(data['_tag'] == tagstr)
|
||||
|
||||
if data['_type'] == 'error':
|
||||
raise ValueError('Error: {}'.format(data['error']))
|
||||
|
||||
assert(data['_type'] == 'begin')
|
||||
|
||||
# Ideally, we would confirm that this is our "begin", but that
|
||||
# would need the cmd passed into this method, and that would
|
||||
# probably require parsing the cmdline passed to us :-(
|
||||
# assert(data['cmd'] == cmd)
|
||||
|
||||
result = list()
|
||||
error = None
|
||||
|
||||
while True:
|
||||
data, _ = self.sock.recvfrom(1024)
|
||||
data = json.loads(data.decode('utf8'))
|
||||
|
||||
if data['_tag'] != tagstr:
|
||||
# this packet is not for us, ignore it
|
||||
continue
|
||||
|
||||
if data['_type'] == 'error':
|
||||
# we still expect an end packet, so save the error
|
||||
error = ValueError('Error: {}'.format(data['error']))
|
||||
continue
|
||||
|
||||
if data['_type'] == 'end':
|
||||
if error:
|
||||
raise error
|
||||
return result
|
||||
|
||||
if data['_type'] != 'row':
|
||||
raise ValueError('Unknown data type {} from '
|
||||
'edge'.format(data['_type']))
|
||||
|
||||
# remove our boring metadata
|
||||
del data['_tag']
|
||||
del data['_type']
|
||||
|
||||
if self.debug:
|
||||
print(data)
|
||||
|
||||
result.append(data)
|
||||
|
||||
def _call(self, msgtype, cmdline):
|
||||
"""Perform a rpc call"""
|
||||
tagstr, msgstr = self._cmdstr(msgtype, cmdline)
|
||||
self.sock.sendto(msgstr.encode('utf8'), (self.address, self.port))
|
||||
return self._rx(tagstr)
|
||||
|
||||
def read(self, cmdline):
|
||||
return self._call('r', cmdline)
|
||||
|
||||
def write(self, cmdline):
|
||||
return self._call('w', cmdline)
|
||||
# We share the implementation of the RPC class with the n2n-ctl script. We
|
||||
# cannot just import the module as 'n2n-ctl' has a dash in its name :-(
|
||||
JsonUDP = import_filename('n2nctl', 'n2n-ctl').JsonUDP
|
||||
|
||||
|
||||
pages = {
|
||||
|
|
|
@ -1,40 +1,47 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# This expects to find the tests in the tools dir and the expected results
|
||||
# in the tests dir.
|
||||
# Run with the name of a test list file.
|
||||
#
|
||||
# This expects to find the tests in the tools dir or scripts dir and the
|
||||
# expected results in the tests dir.
|
||||
|
||||
TESTS="
|
||||
tests-auth
|
||||
tests-compress
|
||||
tests-elliptic
|
||||
tests-hashing
|
||||
tests-transform
|
||||
tests-wire
|
||||
"
|
||||
# boilerplate so we can support whaky cmake dirs
|
||||
[ -z "$TOPDIR" ] && TOPDIR="."
|
||||
[ -z "$BINDIR" ] && BINDIR="."
|
||||
export TOPDIR
|
||||
export BINDIR
|
||||
|
||||
TOOLSDIR=tools
|
||||
TESTDATA=tests
|
||||
if [ -z "$1" ]; then
|
||||
echo need test list filename
|
||||
exit 1
|
||||
fi
|
||||
TESTLIST="$1"
|
||||
LISTDIR=$(dirname "$TESTLIST")
|
||||
|
||||
# Allow both dirs be overidden
|
||||
[ -n "$1" ] && TOOLSDIR="$1"
|
||||
[ -n "$2" ] && TESTDATA="$2"
|
||||
|
||||
# Confirm we have all the tools and data
|
||||
for i in $TESTS; do
|
||||
if [ ! -e "$TOOLSDIR/$i" ]; then
|
||||
echo "Could not find test $TOOLSDIR/$i"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -e "$TESTDATA/$i.expected" ]; then
|
||||
echo "Could not find testdata $TESTDATA/$i.expected"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
TESTS=$(sed -e "s/#.*//" "$TESTLIST")
|
||||
|
||||
# Actually run the tests
|
||||
set -e
|
||||
for i in $TESTS; do
|
||||
echo "$TOOLSDIR/$i >$TESTDATA/$i.out"
|
||||
"$TOOLSDIR/$i" >"$TESTDATA/$i.out"
|
||||
cmp "$TESTDATA/$i.expected" "$TESTDATA/$i.out"
|
||||
# Look in several places for the test program
|
||||
if [ -e "$BINDIR/$i" ]; then
|
||||
TEST="$BINDIR/$i"
|
||||
elif [ -e "$BINDIR/tools/$i" ]; then
|
||||
TEST="$BINDIR/tools/$i"
|
||||
elif [ -e "$LISTDIR/../scripts/$i" ]; then
|
||||
TEST="$LISTDIR/../scripts/$i"
|
||||
else
|
||||
echo "Could not find test $i"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
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
|
||||
|
|
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 "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
|
||||
typedef struct n2n_mgmt_handler {
|
||||
typedef struct mgmt_handler {
|
||||
int flags;
|
||||
char *cmd;
|
||||
char *help;
|
||||
void (*func)(n2n_edge_t *eee, char *udp_buf, struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv);
|
||||
} n2n_mgmt_handler_t;
|
||||
void (*func)(mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv);
|
||||
} mgmt_handler_t;
|
||||
|
||||
static void mgmt_error (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, char *tag, char *msg) {
|
||||
size_t msg_len;
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
"{"
|
||||
"\"_tag\":\"%s\","
|
||||
"\"_type\":\"error\","
|
||||
"\"error\":\"%s\"}\n",
|
||||
tag,
|
||||
msg);
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
/*
|
||||
* Event topic names are defined in this structure
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
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 msg_len;
|
||||
size_t gen_json_1str (strbuf_t *buf, char *tag, char *_type, char *key, char *val) {
|
||||
return snprintf(buf->str, buf->size,
|
||||
"{"
|
||||
"\"_tag\":\"%s\","
|
||||
"\"_type\":\"%s\","
|
||||
"\"%s\":\"%s\"}\n",
|
||||
tag,
|
||||
_type,
|
||||
key,
|
||||
val);
|
||||
}
|
||||
|
||||
if(type==N2N_MGMT_WRITE) {
|
||||
*eee->keep_running = 0;
|
||||
size_t gen_json_1uint (strbuf_t *buf, char *tag, char *_type, char *key, unsigned int val) {
|
||||
return snprintf(buf->str, buf->size,
|
||||
"{"
|
||||
"\"_tag\":\"%s\","
|
||||
"\"_type\":\"%s\","
|
||||
"\"%s\":%u}\n",
|
||||
tag,
|
||||
_type,
|
||||
key,
|
||||
val);
|
||||
}
|
||||
|
||||
static void send_json_1str (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, char *val) {
|
||||
size_t msg_len = gen_json_1str(buf, req->tag, _type, key, val);
|
||||
send_reply(req, buf, msg_len);
|
||||
}
|
||||
|
||||
static void send_json_1uint (mgmt_req_t *req, strbuf_t *buf, char *_type, char *key, unsigned int val) {
|
||||
size_t msg_len = 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;
|
||||
}
|
||||
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
"{"
|
||||
"\"_tag\":\"%s\","
|
||||
"\"_type\":\"row\","
|
||||
"\"keep_running\":%u}\n",
|
||||
tag,
|
||||
*eee->keep_running);
|
||||
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
send_json_1uint(req, buf, "row", "keep_running", *req->eee->keep_running);
|
||||
}
|
||||
|
||||
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) {
|
||||
size_t msg_len;
|
||||
static void mgmt_verbose (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) {
|
||||
|
||||
if(type==N2N_MGMT_WRITE) {
|
||||
if(req->type==N2N_MGMT_WRITE) {
|
||||
if(argv) {
|
||||
setTraceLevel(strtoul(argv, NULL, 0));
|
||||
}
|
||||
}
|
||||
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
"{"
|
||||
"\"_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));
|
||||
send_json_1uint(req, buf, "row", "traceLevel", getTraceLevel());
|
||||
}
|
||||
|
||||
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) {
|
||||
size_t msg_len;
|
||||
static void mgmt_communities (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) {
|
||||
|
||||
if(eee->conf.header_encryption != HEADER_ENCRYPTION_NONE) {
|
||||
mgmt_error(eee, udp_buf, sender_sock, tag, "noaccess");
|
||||
if(req->eee->conf.header_encryption != HEADER_ENCRYPTION_NONE) {
|
||||
mgmt_error(req, buf, "noaccess");
|
||||
return;
|
||||
}
|
||||
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
"{"
|
||||
"\"_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));
|
||||
send_json_1str(req, buf, "row", "community", (char *)req->eee->conf.community_name);
|
||||
}
|
||||
|
||||
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;
|
||||
struct peer_info *peer, *tmpPeer;
|
||||
macstr_t mac_buf;
|
||||
n2n_sock_str_t sockbuf;
|
||||
selection_criterion_str_t sel_buf;
|
||||
|
||||
HASH_ITER(hh, eee->conf.supernodes, peer, tmpPeer) {
|
||||
HASH_ITER(hh, req->eee->conf.supernodes, peer, tmpPeer) {
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
|
@ -116,7 +205,7 @@ static void mgmt_supernodes (n2n_edge_t *eee, char *udp_buf, const struct sockad
|
|||
* - do we care?
|
||||
*/
|
||||
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
msg_len = snprintf(buf->str, buf->size,
|
||||
"{"
|
||||
"\"_tag\":\"%s\","
|
||||
"\"_type\":\"row\","
|
||||
|
@ -128,28 +217,27 @@ static void mgmt_supernodes (n2n_edge_t *eee, char *udp_buf, const struct sockad
|
|||
"\"selection\":\"%s\","
|
||||
"\"last_seen\":%li,"
|
||||
"\"uptime\":%li}\n",
|
||||
tag,
|
||||
req->tag,
|
||||
peer->version,
|
||||
peer->purgeable,
|
||||
(peer == eee->curr_sn) ? (eee->sn_wait ? 2 : 1 ) : 0,
|
||||
(peer == req->eee->curr_sn) ? (req->eee->sn_wait ? 2 : 1 ) : 0,
|
||||
is_null_mac(peer->mac_addr) ? "" : macaddr_str(mac_buf, peer->mac_addr),
|
||||
sock_to_cstr(sockbuf, &(peer->sock)),
|
||||
sn_selection_criterion_str(eee, sel_buf, peer),
|
||||
sn_selection_criterion_str(req->eee, sel_buf, peer),
|
||||
peer->last_seen,
|
||||
peer->uptime);
|
||||
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
send_reply(req, buf, msg_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void mgmt_edges_row (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, char *tag, struct peer_info *peer, char *mode) {
|
||||
static void mgmt_edges_row (mgmt_req_t *req, strbuf_t *buf, struct peer_info *peer, char *mode) {
|
||||
size_t msg_len;
|
||||
macstr_t mac_buf;
|
||||
n2n_sock_str_t sockbuf;
|
||||
dec_ip_bit_str_t ip_bit_str = {'\0'};
|
||||
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
msg_len = snprintf(buf->str, buf->size,
|
||||
"{"
|
||||
"\"_tag\":\"%s\","
|
||||
"\"_type\":\"row\","
|
||||
|
@ -163,7 +251,7 @@ static void mgmt_edges_row (n2n_edge_t *eee, char *udp_buf, const struct sockadd
|
|||
"\"last_p2p\":%li,\n"
|
||||
"\"last_sent_query\":%li,\n"
|
||||
"\"last_seen\":%li}\n",
|
||||
tag,
|
||||
req->tag,
|
||||
mode,
|
||||
(peer->dev_addr.net_addr == 0) ? "" : ip_subnet_to_str(ip_bit_str, &peer->dev_addr),
|
||||
peer->purgeable,
|
||||
|
@ -175,111 +263,113 @@ static void mgmt_edges_row (n2n_edge_t *eee, char *udp_buf, const struct sockadd
|
|||
peer->last_sent_query,
|
||||
peer->last_seen);
|
||||
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
send_reply(req, buf, msg_len);
|
||||
}
|
||||
|
||||
static void mgmt_edges (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) {
|
||||
static void mgmt_edges (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) {
|
||||
struct peer_info *peer, *tmpPeer;
|
||||
|
||||
// dump nodes with forwarding through supernodes
|
||||
HASH_ITER(hh, eee->pending_peers, peer, tmpPeer) {
|
||||
mgmt_edges_row(eee, udp_buf, sender_sock, tag, peer, "pSp");
|
||||
HASH_ITER(hh, req->eee->pending_peers, peer, tmpPeer) {
|
||||
mgmt_edges_row(req, buf, peer, "pSp");
|
||||
}
|
||||
|
||||
// dump peer-to-peer nodes
|
||||
HASH_ITER(hh, eee->known_peers, peer, tmpPeer) {
|
||||
mgmt_edges_row(eee, udp_buf, sender_sock, tag, peer, "p2p");
|
||||
HASH_ITER(hh, req->eee->known_peers, peer, tmpPeer) {
|
||||
mgmt_edges_row(req, 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;
|
||||
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
msg_len = snprintf(buf->str, buf->size,
|
||||
"{"
|
||||
"\"_tag\":\"%s\","
|
||||
"\"_type\":\"row\","
|
||||
"\"start_time\":%lu,"
|
||||
"\"last_super\":%ld,"
|
||||
"\"last_p2p\":%ld}\n",
|
||||
tag,
|
||||
eee->start_time,
|
||||
eee->last_sup,
|
||||
eee->last_p2p);
|
||||
req->tag,
|
||||
req->eee->start_time,
|
||||
req->eee->last_sup,
|
||||
req->eee->last_p2p);
|
||||
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
send_reply(req, buf, msg_len);
|
||||
}
|
||||
|
||||
static void mgmt_packetstats (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) {
|
||||
static void mgmt_packetstats (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) {
|
||||
size_t msg_len;
|
||||
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
msg_len = snprintf(buf->str, buf->size,
|
||||
"{"
|
||||
"\"_tag\":\"%s\","
|
||||
"\"_type\":\"row\","
|
||||
"\"type\":\"transop\","
|
||||
"\"tx_pkt\":%lu,"
|
||||
"\"rx_pkt\":%lu}\n",
|
||||
tag,
|
||||
eee->transop.tx_cnt,
|
||||
eee->transop.rx_cnt);
|
||||
req->tag,
|
||||
req->eee->transop.tx_cnt,
|
||||
req->eee->transop.rx_cnt);
|
||||
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
send_reply(req, buf, msg_len);
|
||||
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
msg_len = snprintf(buf->str, buf->size,
|
||||
"{"
|
||||
"\"_tag\":\"%s\","
|
||||
"\"_type\":\"row\","
|
||||
"\"type\":\"p2p\","
|
||||
"\"tx_pkt\":%u,"
|
||||
"\"rx_pkt\":%u}\n",
|
||||
tag,
|
||||
eee->stats.tx_p2p,
|
||||
eee->stats.rx_p2p);
|
||||
req->tag,
|
||||
req->eee->stats.tx_p2p,
|
||||
req->eee->stats.rx_p2p);
|
||||
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
send_reply(req, buf, msg_len);
|
||||
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
msg_len = snprintf(buf->str, buf->size,
|
||||
"{"
|
||||
"\"_tag\":\"%s\","
|
||||
"\"_type\":\"row\","
|
||||
"\"type\":\"super\","
|
||||
"\"tx_pkt\":%u,"
|
||||
"\"rx_pkt\":%u}\n",
|
||||
tag,
|
||||
eee->stats.tx_sup,
|
||||
eee->stats.rx_sup);
|
||||
req->tag,
|
||||
req->eee->stats.tx_sup,
|
||||
req->eee->stats.rx_sup);
|
||||
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
send_reply(req, buf, msg_len);
|
||||
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
msg_len = snprintf(buf->str, buf->size,
|
||||
"{"
|
||||
"\"_tag\":\"%s\","
|
||||
"\"_type\":\"row\","
|
||||
"\"type\":\"super_broadcast\","
|
||||
"\"tx_pkt\":%u,"
|
||||
"\"rx_pkt\":%u}\n",
|
||||
tag,
|
||||
eee->stats.tx_sup_broadcast,
|
||||
eee->stats.rx_sup_broadcast);
|
||||
req->tag,
|
||||
req->eee->stats.tx_sup_broadcast,
|
||||
req->eee->stats.rx_sup_broadcast);
|
||||
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
send_reply(req, buf, msg_len);
|
||||
}
|
||||
|
||||
static void mgmt_unimplemented (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) {
|
||||
static void mgmt_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 = "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 = "timestamps", .help = "Event timestamps", .func = mgmt_timestamps},
|
||||
{ .cmd = "packetstats", .help = "traffic counters", .func = mgmt_packetstats},
|
||||
{ .cmd = "post.test", .help = "send a test event", .func = mgmt_post_test},
|
||||
{ .cmd = "help", .flags = FLAG_WROK, .help = "Show JSON commands", .func = mgmt_help},
|
||||
{ .cmd = 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;
|
||||
n2n_mgmt_handler_t *handler;
|
||||
|
||||
/*
|
||||
* Even though this command is readonly, we deliberately do not check
|
||||
* the type - allowing help replies to both read and write requests
|
||||
*/
|
||||
|
||||
for( handler=mgmt_handlers; handler->cmd; handler++ ) {
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
int i;
|
||||
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\","
|
||||
"\"_type\":\"row\","
|
||||
"\"cmd\":\"%s\","
|
||||
"\"help\":\"%s\"}\n",
|
||||
tag,
|
||||
handler->cmd,
|
||||
handler->help);
|
||||
req->tag,
|
||||
mgmt_handlers[i].cmd,
|
||||
mgmt_handlers[i].help);
|
||||
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
send_reply(req, buf, msg_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* Writes are possibly dangerous, so they need a fake password
|
||||
*/
|
||||
static int mgmt_auth (n2n_edge_t *eee, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *auth, char *argv0, char *argv) {
|
||||
static int mgmt_auth (mgmt_req_t *req, char *auth, char *argv0, char *argv) {
|
||||
|
||||
if(auth) {
|
||||
/* If we have an auth key, it must match */
|
||||
if(eee->conf.mgmt_password_hash == pearson_hash_64((uint8_t*)auth, strlen(auth))) {
|
||||
if(req->eee->conf.mgmt_password_hash == pearson_hash_64((uint8_t*)auth, strlen(auth))) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* if we dont have an auth key, we can still read */
|
||||
if(type == N2N_MGMT_READ) {
|
||||
if(req->type == N2N_MGMT_READ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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];
|
||||
enum n2n_mgmt_type type;
|
||||
char *typechar;
|
||||
char *options;
|
||||
char *argv0;
|
||||
char *argv;
|
||||
char *tag;
|
||||
char *flagstr;
|
||||
int flags;
|
||||
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 */
|
||||
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);
|
||||
|
||||
/* we reuse the buffer already on the stack for all our strings */
|
||||
STRBUF_INIT(buf, udp_buf);
|
||||
|
||||
typechar = strtok(cmdlinebuf, " \r\n");
|
||||
if(!typechar) {
|
||||
/* should not happen */
|
||||
mgmt_error(eee, udp_buf, sender_sock, "-1", "notype");
|
||||
mgmt_error(req, buf, "notype");
|
||||
return;
|
||||
}
|
||||
if(*typechar == 'r') {
|
||||
type=N2N_MGMT_READ;
|
||||
req->type=N2N_MGMT_READ;
|
||||
} else if(*typechar == 'w') {
|
||||
type=N2N_MGMT_WRITE;
|
||||
req->type=N2N_MGMT_WRITE;
|
||||
} else if(*typechar == 's') {
|
||||
req->type=N2N_MGMT_SUB;
|
||||
} else {
|
||||
/* dunno how we got here */
|
||||
mgmt_error(eee, udp_buf, sender_sock, "-1", "badtype");
|
||||
mgmt_error(req, buf, "badtype");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Extract the tag to use in all reply packets */
|
||||
options = strtok(NULL, " \r\n");
|
||||
if(!options) {
|
||||
mgmt_error(eee, udp_buf, sender_sock, "-1", "nooptions");
|
||||
mgmt_error(req, buf, "nooptions");
|
||||
return;
|
||||
}
|
||||
|
||||
argv0 = strtok(NULL, " \r\n");
|
||||
if(!argv0) {
|
||||
mgmt_error(eee, udp_buf, sender_sock, "-1", "nocmd");
|
||||
mgmt_error(req, buf, "nocmd");
|
||||
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
|
||||
*/
|
||||
tag = strtok(options, ":");
|
||||
char *tagp = strtok(options, ":");
|
||||
strncpy(req->tag, tagp, sizeof(req->tag)-1);
|
||||
req->tag[sizeof(req->tag)-1] = '\0';
|
||||
|
||||
flagstr = strtok(NULL, ":");
|
||||
if(flagstr) {
|
||||
flags = strtoul(flagstr, NULL, 16);
|
||||
|
@ -416,23 +612,41 @@ void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in se
|
|||
auth = NULL;
|
||||
}
|
||||
|
||||
if(!mgmt_auth(eee, sender_sock, type, auth, argv0, argv)) {
|
||||
mgmt_error(eee, udp_buf, sender_sock, tag, "badauth");
|
||||
if(!mgmt_auth(req, auth, argv0, argv)) {
|
||||
mgmt_error(req, buf, "badauth");
|
||||
return;
|
||||
}
|
||||
|
||||
for( handler=mgmt_handlers; handler->cmd; handler++ ) {
|
||||
if(0 == strcmp(handler->cmd, argv0)) {
|
||||
break;
|
||||
if(req->type == N2N_MGMT_SUB) {
|
||||
int handler;
|
||||
lookup_handler(handler, mgmt_event_names, argv0);
|
||||
if(handler == -1) {
|
||||
mgmt_error(req, buf, "unknowntopic");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!handler->cmd) {
|
||||
mgmt_error(eee, udp_buf, sender_sock, tag, "unknowncmd");
|
||||
|
||||
int topic = mgmt_event_names[handler].topic;
|
||||
if(mgmt_event_subscribers[topic].type == N2N_MGMT_SUB) {
|
||||
send_json_1str(&mgmt_event_subscribers[topic], buf,
|
||||
"unsubscribed", "topic", argv0);
|
||||
send_json_1str(req, buf, "replacing", "topic", argv0);
|
||||
}
|
||||
|
||||
memcpy(&mgmt_event_subscribers[topic], req, sizeof(*req));
|
||||
|
||||
send_json_1str(req, buf, "subscribe", "topic", argv0);
|
||||
return;
|
||||
}
|
||||
|
||||
if((type==N2N_MGMT_WRITE) && !(handler->flags & FLAG_WROK)) {
|
||||
mgmt_error(eee, udp_buf, sender_sock, tag, "readonly");
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -442,16 +656,243 @@ void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in se
|
|||
* that make our JSON invalid.
|
||||
* - do we care?
|
||||
*/
|
||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE,
|
||||
"{\"_tag\":\"%s\",\"_type\":\"begin\",\"cmd\":\"%s\"}\n", tag, argv0);
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
send_json_1str(req, buf, "begin", "cmd", argv0);
|
||||
|
||||
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,
|
||||
"{\"_tag\":\"%s\",\"_type\":\"end\"}\n", tag);
|
||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0,
|
||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in));
|
||||
send_json_1str(req, buf, "end", "cmd", argv0);
|
||||
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);
|
||||
if(scan_tmp != NULL) {
|
||||
HASH_DEL(eee->known_peers, scan_tmp);
|
||||
mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan);
|
||||
free(scan);
|
||||
scan = scan_tmp;
|
||||
memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t));
|
||||
|
@ -828,6 +829,7 @@ static void peer_set_p2p_confirmed (n2n_edge_t * eee,
|
|||
|
||||
HASH_ADD_PEER(eee->known_peers, scan);
|
||||
scan->last_p2p = now;
|
||||
mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_ADD_P2P,scan);
|
||||
|
||||
traceEvent(TRACE_DEBUG, "p2p connection established: %s [%s]",
|
||||
macaddr_str(mac_buf, mac),
|
||||
|
@ -994,6 +996,7 @@ static void check_known_peer_sock_change (n2n_edge_t *eee,
|
|||
sock_to_cstr(sockbuf2, peer));
|
||||
/* The peer has changed public socket. It can no longer be assumed to be reachable. */
|
||||
HASH_DEL(eee->known_peers, scan);
|
||||
mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan);
|
||||
free(scan);
|
||||
|
||||
register_with_new_peer(eee, from_supernode, via_multicast, mac, dev_addr, dev_desc, peer);
|
||||
|
@ -1821,238 +1824,6 @@ static char *get_ip_from_arp (dec_ip_str_t buf, const n2n_mac_t req_mac) {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/** Read a datagram from the management UDP socket and take appropriate
|
||||
* action. */
|
||||
static void readFromMgmtSocket (n2n_edge_t *eee) {
|
||||
|
||||
char udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */
|
||||
ssize_t recvlen;
|
||||
/* ssize_t sendlen; */
|
||||
struct sockaddr_in sender_sock;
|
||||
socklen_t i;
|
||||
size_t msg_len;
|
||||
time_t now;
|
||||
struct peer_info *peer, *tmpPeer;
|
||||
macstr_t mac_buf;
|
||||
char time_buf[10]; /* 9 digits + 1 terminating zero */
|
||||
char uptime_buf[11]; /* 10 digits + 1 terminating zero */
|
||||
/* dec_ip_bit_str_t ip_bit_str = {'\0'}; */
|
||||
/* dec_ip_str_t ip_str = {'\0'}; */
|
||||
in_addr_t net;
|
||||
n2n_sock_str_t sockbuf;
|
||||
uint32_t num_pending_peers = 0;
|
||||
uint32_t num_known_peers = 0;
|
||||
uint32_t num = 0;
|
||||
selection_criterion_str_t sel_buf;
|
||||
|
||||
|
||||
now = time(NULL);
|
||||
i = sizeof(sender_sock);
|
||||
recvlen = recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/,
|
||||
(struct sockaddr *) &sender_sock, (socklen_t *) &i);
|
||||
|
||||
if(recvlen < 0) {
|
||||
traceEvent(TRACE_WARNING, "mgmt recvfrom failed: %d - %s", errno, strerror(errno));
|
||||
return; /* failed to receive data from UDP */
|
||||
}
|
||||
|
||||
/* avoid parsing any uninitialized junk from the stack */
|
||||
udp_buf[recvlen] = 0;
|
||||
|
||||
if((0 == memcmp(udp_buf, "help", 4)) || (0 == memcmp(udp_buf, "?", 1))) {
|
||||
msg_len = 0;
|
||||
|
||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_len),
|
||||
"Help for edge management console:\n"
|
||||
"\tstop | Gracefully exit edge\n"
|
||||
"\thelp | This help message\n"
|
||||
"\t+verb | Increase verbosity of logging\n"
|
||||
"\t-verb | Decrease verbosity of logging\n"
|
||||
"\tr ... | start query with JSON reply\n"
|
||||
"\tw ... | start update with JSON reply\n"
|
||||
"\t<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) {
|
||||
|
@ -2112,6 +1883,7 @@ static int find_peer_destination (n2n_edge_t * eee,
|
|||
* since the peer address may have changed. */
|
||||
traceEvent(TRACE_DEBUG, "refreshing idle known peer");
|
||||
HASH_DEL(eee->known_peers, scan);
|
||||
mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_DEL_P2P,scan);
|
||||
free(scan);
|
||||
/* NOTE: registration will be performed upon the receival of the next response packet */
|
||||
} else {
|
||||
|
|
|
@ -636,6 +636,8 @@ size_t purge_peer_list (struct peer_info **peer_list,
|
|||
}
|
||||
}
|
||||
HASH_DEL(*peer_list, scan);
|
||||
mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_PURGE,scan);
|
||||
/* FIXME: generates events for more than just p2p */
|
||||
retval++;
|
||||
free(scan);
|
||||
}
|
||||
|
@ -652,6 +654,8 @@ size_t clear_peer_list (struct peer_info ** peer_list) {
|
|||
|
||||
HASH_ITER(hh, *peer_list, scan, tmp) {
|
||||
HASH_DEL(*peer_list, scan);
|
||||
mgmt_event_post(N2N_EVENT_PEER,N2N_EVENT_PEER_CLEAR,scan);
|
||||
/* FIXME: generates events for more than just p2p */
|
||||
retval++;
|
||||
free(scan);
|
||||
}
|
||||
|
|
|
@ -26,13 +26,18 @@
|
|||
|
||||
int load_allowed_sn_community (n2n_sn_t *sss); /* defined in sn_utils.c */
|
||||
|
||||
enum n2n_mgmt_type {
|
||||
N2N_MGMT_READ = 0,
|
||||
N2N_MGMT_WRITE = 1,
|
||||
};
|
||||
|
||||
#define FLAG_WROK 1
|
||||
typedef struct n2n_mgmt_handler {
|
||||
typedef struct mgmt_handler {
|
||||
int flags;
|
||||
char *cmd;
|
||||
char *help;
|
||||
void (*func)(n2n_sn_t *sss, char *udp_buf, struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv);
|
||||
} n2n_mgmt_handler_t;
|
||||
} mgmt_handler_t;
|
||||
|
||||
static void mgmt_error (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock, char *tag, char *msg) {
|
||||
size_t msg_len;
|
||||
|
@ -263,7 +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);
|
||||
|
||||
n2n_mgmt_handler_t mgmt_handlers[] = {
|
||||
mgmt_handler_t mgmt_handlers[] = {
|
||||
{ .cmd = "supernodes", .help = "Reserved for edge", .func = mgmt_unimplemented},
|
||||
|
||||
{ .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop},
|
||||
|
@ -279,7 +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) {
|
||||
size_t msg_len;
|
||||
n2n_mgmt_handler_t *handler;
|
||||
mgmt_handler_t *handler;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
void handleMgmtJson_sn (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock) {
|
||||
static void handleMgmtJson (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock) {
|
||||
|
||||
char cmdlinebuf[80];
|
||||
enum n2n_mgmt_type type;
|
||||
|
@ -338,7 +343,7 @@ void handleMgmtJson_sn (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in s
|
|||
char *flagstr;
|
||||
int flags;
|
||||
char *auth;
|
||||
n2n_mgmt_handler_t *handler;
|
||||
mgmt_handler_t *handler;
|
||||
size_t msg_len;
|
||||
|
||||
/* save a copy of the commandline before we reuse the udp_buf */
|
||||
|
@ -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));
|
||||
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,
|
||||
size_t pktsize);
|
||||
|
||||
static int sendto_mgmt (n2n_sn_t *sss,
|
||||
const struct sockaddr_in *sender_sock,
|
||||
const uint8_t *mgmt_buf,
|
||||
size_t mgmt_size);
|
||||
|
||||
static uint16_t reg_lifetime (n2n_sn_t *sss);
|
||||
|
||||
static int update_edge (n2n_sn_t *sss,
|
||||
|
@ -61,7 +56,7 @@ static int sort_communities (n2n_sn_t *sss,
|
|||
time_t* p_last_sort,
|
||||
time_t now);
|
||||
|
||||
static int process_mgmt (n2n_sn_t *sss,
|
||||
int process_mgmt (n2n_sn_t *sss,
|
||||
const struct sockaddr_in *sender_sock,
|
||||
char *mgmt_buf,
|
||||
size_t mgmt_size,
|
||||
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -639,10 +639,24 @@ int main (int argc, char * const argv[]) {
|
|||
scan->socket_fd = sss_node.sock;
|
||||
|
||||
#ifndef WIN32
|
||||
/*
|
||||
* If no uid/gid is specified on the commandline, use the uid/gid of the
|
||||
* first found out of user "n2n" or "nobody"
|
||||
*/
|
||||
if(((pw = getpwnam ("n2n")) != NULL) || ((pw = getpwnam ("nobody")) != NULL)) {
|
||||
/*
|
||||
* If the uid/gid is not set from the CLI, set it from getpwnam
|
||||
* otherwise reset it to zero
|
||||
* (TODO: this looks wrong)
|
||||
*/
|
||||
sss_node.userid = sss_node.userid == 0 ? pw->pw_uid : 0;
|
||||
sss_node.groupid = sss_node.groupid == 0 ? pw->pw_gid : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a non-zero requested uid/gid, attempt to switch to use
|
||||
* those
|
||||
*/
|
||||
if((sss_node.userid != 0) || (sss_node.groupid != 0)) {
|
||||
traceEvent(TRACE_NORMAL, "dropping privileges to uid=%d, gid=%d",
|
||||
(signed int)sss_node.userid, (signed int)sss_node.groupid);
|
||||
|
@ -651,7 +665,6 @@ int main (int argc, char * const argv[]) {
|
|||
if((setgid(sss_node.groupid) != 0)
|
||||
|| (setuid(sss_node.userid) != 0)) {
|
||||
traceEvent(TRACE_ERROR, "unable to drop privileges [%u/%s]", errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
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