Switch to feature-driven linking

This introduces a new way of linking Serval executables and dynamic
libraries from static libraries like libservald.a -- called
"feature-driven" linking.

The Makefile now links servald and serval-tests from libservald.a,
rather than from an explicit list of object (.o) files.  Thanks to the
section-based method for registering functions such as HTTP handlers,
CLI commands and MDP handlers, these object files had become
"stand-alone" and hence were no longer included in the link because
there was no unresolved reference that required them to be linked in.

The new "feature.h" provides the DECLARE_FEATURE(name) macro that each
stand-alone source file uses to declare the named feature(s) it
provides.  Each executable can call the USE_FEATURE(name) macro in any
of its explicitly-linked source files to cause the corresponding
object(s) to be included in the link, eg, servald_features.c.

The DEFINE_BINDING() macro has been extended so that every individual
MDP binding is given a feature name based on its port number macro, eg,
"mdp_binding_MDP_PORT_ECHO".

Some features have been factored into their own separate source files so
they can be omitted or included in a build independently of each other:
- the MDP bindings for MDP_PORT_DNALOOKUP, MDP_PORT_ECHO,
  MDP_PORT_TRACE, MDP_PORT_KEYMAPREQUEST, MDP_PORT_RHIZOME_xxx,
  MDP_PORT_PROBE, MDP_PORT_STUN, MDP_PORT_STUNREQ
- the CLI "log" and "echo" commands
- the CLI "rhizome direct" command

The JNI source files are only compiled if the <jni.h> header is present,
otherwise they are omitted from libservald.so.
This commit is contained in:
Andrew Bettison 2016-10-13 13:28:23 +10:30
parent 8cb3afa7dc
commit 71cbe86566
53 changed files with 1564 additions and 1051 deletions

View File

@ -23,8 +23,6 @@ ALL_SOURCES = \
$(MDP_CLIENT_SOURCES) \
$(SERVAL_DAEMON_SOURCES) \
$(SERVAL_DAEMON_JNI_SOURCES) \
$(TEST_SOURCES) \
$(SERVAL_LIB_SOURCES) \
$(MONITOR_CLIENT_SRCS) \
$(SIMULATOR_SOURCES) \
$(SQLITE3_SOURCES)
@ -32,23 +30,21 @@ ALL_SOURCES = \
SERVAL_DAEMON_OBJS = \
$(addprefix $(OBJSDIR_SERVALD)/, $(SERVAL_CLIENT_SOURCES:.c=.o)) \
$(addprefix $(OBJSDIR_SERVALD)/, $(MDP_CLIENT_SOURCES:.c=.o)) \
$(addprefix $(OBJSDIR_SERVALD)/, $(SERVAL_DAEMON_SOURCES:.c=.o)) \
$(addprefix $(OBJSDIR_SERVALD)/, $(SERVAL_DAEMON_SOURCES:.c=.o))
ifeq (@HAVE_JNI_H@,yes)
SERVAL_DAEMON_OBJS += \
$(addprefix $(OBJSDIR_SERVALD)/, $(SERVAL_DAEMON_JNI_SOURCES:.c=.o))
endif
SQLITE3_OBJS = \
$(addprefix $(OBJSDIR_SERVALD)/, $(notdir $(SQLITE3_SOURCES:.c=.o)))
SERVALD_OBJS = \
$(SQLITE3_OBJS) \
$(SERVAL_DAEMON_OBJS)
TEST_OBJS = \
$(addprefix $(OBJSDIR_SERVALD)/, $(TEST_SOURCES:.c=.o)) \
$(addprefix $(OBJSDIR_SERVALD)/, $(SERVAL_CLIENT_SOURCES:.c=.o))
LIB_SERVAL_OBJS = \
$(addprefix $(OBJSDIR_LIB)/, $(SERVAL_CLIENT_SOURCES:.c=.o)) \
$(addprefix $(OBJSDIR_LIB)/, $(SERVAL_LIB_SOURCES:.c=.o)) \
$(addprefix $(OBJSDIR_LIB)/, $(MDP_CLIENT_SOURCES:.c=.o))
MONITOR_CLIENT_OBJS = \
$(addprefix $(OBJSDIR_LIB)/, $(SERVAL_CLIENT_SOURCES:.c=.o)) \
$(addprefix $(OBJSDIR_LIB)/, $(SERVAL_LIB_SOURCES:.c=.o)) \
$(addprefix $(OBJSDIR_LIB)/, $(MONITOR_CLIENT_SRCS:.c=.o))
SIMULATOR_OBJS = \
$(addprefix $(OBJSDIR_TOOLS)/, $(SIMULATOR_SOURCES:.c=.o))
@ -93,7 +89,7 @@ DEFS= @DEFS@
all: libs servald servaldwrap test
libs: libservald.so libservald.a \
libs: libservald.so \
libservalclient.so libservalclient.a \
libmonitorclient.so libmonitorclient.a
@ -108,7 +104,7 @@ uninstall:
clean:
@$(RM) -r $(OBJSDIRS:%=%/*) \
servald \
libservald.so libservald.a \
libservald.a \
libservalclient.so libservalclient.a \
libmonitorclient.so libmonitorclient.a \
tfw_createfile directory_service fakeradio simulator serval-tests
@ -223,7 +219,6 @@ $(OBJSDIR_LIB)/%.o: $(SOURCE_PREFIX)%.c
$(SERVAL_DAEMON_OBJS): $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS)
$(SERVALD_OBJS): $(SOURCE_PREFIX)Makefile
$(LIB_SERVAL_OBJS): $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS)
$(TEST_OBJS): $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS)
$(OBJSDIR_TOOLS)/tfw_createfile.o: $(SOURCE_PREFIX)Makefile $(SOURCE_PREFIX)str.h
$(OBJSDIR_TOOLS)/directory_service.o: $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS)
$(MONITOR_CLIENT_OBJS): $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS)
@ -231,57 +226,62 @@ $(SIMULATOR_OBJS): $(SOURCE_PREFIX)Makefile $(PREFIXED_HEADERS)
# Rules for main targets.
servald: $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o
libservald.a: $(SERVALD_OBJS) \
$(OBJSDIR_TOOLS)/version.o
@echo AR $@
@$(AR) -cr $@ $^
libservald.so: \
$(OBJSDIR_SERVALD)/servald_features.o \
$(OBJSDIR_SERVALD)/jni_commandline.o \
$(OBJSDIR_SERVALD)/jni_server.o \
libservald.a
@echo LINK $@
@$(CC) -Wall -o $@ $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o $(LDFLAGS)
@$(CC) -Wall -shared -o $@ $^ $(LDFLAGS)
servald: $(OBJSDIR_SERVALD)/servald_features.o libservald.a
@echo LINK $@
@$(CC) -Wall -o $@ $^ $(LDFLAGS)
servaldwrap: $(OBJSDIR_SERVALD)/servalwrap.o $(OBJSDIR_TOOLS)/version.o
@echo LINK $@
@$(CC) -Wall -o $@ $^ $(LDFLAGS)
serval-tests: $(TEST_OBJS) $(OBJSDIR_TOOLS)/version.o
serval-tests: $(OBJSDIR_SERVALD)/test_features.o libservald.a
@echo LINK $@
@$(CC) -Wall -o $@ $(TEST_OBJS) $(OBJSDIR_TOOLS)/version.o $(LDFLAGS)
@$(CC) -Wall -o $@ $^ $(LDFLAGS)
directory_service: $(OBJSDIR_TOOLS)/directory_service.o libservalclient.a
@echo LINK $@
@$(CC) -Wall -o $@ $(OBJSDIR_TOOLS)/directory_service.o libservalclient.a $(LDFLAGS)
@$(CC) -Wall -o $@ $^ $(LDFLAGS)
tfw_createfile: $(OBJSDIR_TOOLS)/tfw_createfile.o libservalclient.a
@echo LINK $@
@$(CC) -Wall -o $@ $(OBJSDIR_TOOLS)/tfw_createfile.o libservalclient.a $(LDFLAGS)
@$(CC) -Wall -o $@ $^ $(LDFLAGS)
fakeradio: $(OBJSDIR_TOOLS)/fakeradio.o libservalclient.a
@echo LINK $@
@$(CC) -Wall -o $@ $(OBJSDIR_TOOLS)/fakeradio.o libservalclient.a $(LDFLAGS)
@$(CC) -Wall -o $@ $^ $(LDFLAGS)
simulator: $(SIMULATOR_OBJS) libservalclient.a
@echo LINK $@
@$(CC) -Wall -o $@ $(SIMULATOR_OBJS) libservalclient.a $(LDFLAGS)
libservalclient.so: $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o
@echo AR $@
@$(CC) -Wall -shared -o $@ $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o
@$(CC) -Wall -o $@ $^ $(LDFLAGS)
libservalclient.a: $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o
@echo AR $@
@$(AR) -cr $@ $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o
@$(AR) -cr $@ $^
libservald.so: $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o
@echo LINK $@
@$(CC) -Wall -shared -o $@ $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o $(LDFLAGS)
libservald.a: $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o
libservalclient.so: $(LIB_SERVAL_OBJS) $(OBJSDIR_TOOLS)/version.o
@echo AR $@
@$(AR) -cr $@ $(SERVALD_OBJS) $(OBJSDIR_TOOLS)/version.o
libmonitorclient.so: $(MONITOR_CLIENT_OBJS) $(OBJSDIR_TOOLS)/version.o
@echo LINK $@
@$(CC) -Wall -shared -o $@ $(MONITOR_CLIENT_OBJS) $(OBJSDIR_TOOLS)/version.o $(LDFLAGS)
@$(CC) -Wall -shared -o $@ $^
libmonitorclient.a: $(MONITOR_CLIENT_OBJS) $(OBJSDIR_TOOLS)/version.o
@echo AR $@
@$(AR) -cr $@ $(MONITOR_CLIENT_OBJS) $(OBJSDIR_TOOLS)/version.o
@$(AR) -cr $@ $^
libmonitorclient.so: $(MONITOR_CLIENT_OBJS) $(OBJSDIR_TOOLS)/version.o
@echo LINK $@
@$(CC) -Wall -shared -o $@ $^ $(LDFLAGS)
# Helpful target to update the COPYRIGHT.txt file by harvesting copyright
# information from the contents of all the source and header files. This

View File

@ -19,7 +19,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "commandline.h"
#include "serval.h"
#include "conf.h"
#include "str.h"
#include "cli_stdio.h"
@ -32,20 +31,6 @@ static int app_usage(const struct cli_parsed *parsed, struct cli_context *UNUSED
return cli_usage_parsed(parsed, XPRINTF_STDIO(stdout));
}
DEFINE_CMD(version_message,CLIFLAG_PERMISSIVE_CONFIG,
"Display copyright information.",
"version|copyright");
static int version_message(const struct cli_parsed *UNUSED(parsed), struct cli_context *UNUSED(context))
{
printf("Serval DNA version %s\n%s\n", version_servald, copyright_servald);
printf("\
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n\
This is free software: you are free to change and redistribute it.\n\
There is NO WARRANTY, to the extent permitted by law.\n\
");
return 0;
}
/* Parse the command line and load the configuration. If a command was found then execute the
* parsed command and return its return value.
*
@ -60,6 +45,8 @@ int commandline_main(struct cli_context *context, const char *argv0, int argc, c
{
fd_clearstats();
IN();
cf_init();
struct cli_parsed parsed;
int result = cli_parse(argc, args, SECTION_START(commands), SECTION_END(commands), &parsed);
@ -108,41 +95,3 @@ int commandline_main_stdio(FILE *output, const char *argv0, int argc, const char
return commandline_main(&cli_context, argv0, argc, args);
}
DEFINE_CMD(app_echo,CLIFLAG_PERMISSIVE_CONFIG,
"Output the supplied string.",
"echo","[-e]","[--]","...");
static int app_echo(const struct cli_parsed *parsed, struct cli_context *context)
{
DEBUG_cli_parsed(verbose, parsed);
int escapes = !cli_arg(parsed, "-e", NULL, NULL, NULL);
unsigned i;
for (i = parsed->varargi; i < parsed->argc; ++i) {
const char *arg = parsed->args[i];
DEBUGF(verbose, "echo:argv[%d]=\"%s\"", i, arg);
if (escapes) {
char buf[strlen(arg)];
size_t len = strn_fromprint(buf, sizeof buf, arg, 0, '\0', NULL);
cli_write(context, buf, len);
} else
cli_puts(context, arg);
cli_delim(context, NULL);
}
return 0;
}
DEFINE_CMD(app_log,CLIFLAG_PERMISSIVE_CONFIG,
"Log the supplied message at given level.",
"log","error|warn|hint|info|debug","<message>");
static int app_log(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
{
DEBUG_cli_parsed(verbose, parsed);
assert(parsed->argc == 3);
const char *lvl = parsed->args[1];
const char *msg = parsed->args[2];
int level = string_to_log_level(lvl);
if (level == LOG_LEVEL_INVALID)
return WHYF("invalid log level: %s", lvl);
logMessage(level, __NOWHERE__, "%s", msg);
return 0;
}

View File

@ -27,6 +27,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "mdp_client.h"
#include "server.h"
DEFINE_FEATURE(cli_config);
DEFINE_CMD(app_config_schema, CLIFLAG_PERMISSIVE_CONFIG,
"Display configuration schema.",
"config", "schema");

View File

@ -149,6 +149,8 @@ AC_CHECK_HEADERS(
#endif
])
AC_SUBST([HAVE_JNI_H], [$ac_cv_header_jni_h])
dnl libsodium
m4_define([LIBSODIUM_MESSAGE], [
@ -167,6 +169,22 @@ AC_CHECK_HEADERS(
AC_CHECK_LIB(sodium, sodium_init,, [AC_MSG_ERROR([missing libsodium LIBSODIUM_MESSAGE([LIBRARY_PATH])])])
dnl Check if the Linux gettid() and tgkill() system calls are supported.
AC_CACHE_CHECK([Linux gettid() and tgkill()], ac_cv_have_linux_gettid_tgkill, [
ac_cv_have_linux_gettid_tgkill=no
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([
#include <unistd.h>
#include <sys/syscall.h>
#include <signal.h>
],
[syscall(SYS_tgkill, getpid(), syscall(SYS_gettid), SIGHUP)]
)],
[ac_cv_have_linux_gettid_tgkill=yes]
)
])
AS_IF([test "x$ac_cv_have_linux_gettid_tgkill" = xyes], [AC_DEFINE([HAVE_LINUX_THREADS])])
dnl Lazy way of checking for Linux
AS_IF([test "x$ac_cv_header_linux_if_h" = xyes], [AC_DEFINE([USE_ABSTRACT_NAMESPACE])])

48
echo_cli.c Normal file
View File

@ -0,0 +1,48 @@
/*
Serval DNA utilities
Copyright (C) 2014-2015 Serval Project Inc.
Copyright (C) 2016 Flinders University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "feature.h"
#include "commandline.h"
#include "debug.h"
#include "conf.h" // for IF_DEBUG()
DEFINE_FEATURE(cli_echo);
DEFINE_CMD(app_echo, CLIFLAG_PERMISSIVE_CONFIG,
"Output the supplied string.",
"echo","[-e]","[--]","...");
static int app_echo(const struct cli_parsed *parsed, struct cli_context *context)
{
DEBUG_cli_parsed(verbose, parsed);
int escapes = !cli_arg(parsed, "-e", NULL, NULL, NULL);
unsigned i;
for (i = parsed->varargi; i < parsed->argc; ++i) {
const char *arg = parsed->args[i];
DEBUGF(verbose, "echo:argv[%d]=\"%s\"", i, arg);
if (escapes) {
char buf[strlen(arg)];
size_t len = strn_fromprint(buf, sizeof buf, arg, 0, '\0', NULL);
cli_write(context, buf, len);
} else
cli_puts(context, arg);
cli_delim(context, NULL);
}
return 0;
}

66
feature.h Normal file
View File

@ -0,0 +1,66 @@
/*
Serval DNA features
Copyright (C) 2016 Flinders University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __SERVAL_DNA__FEATURE_H
#define __SERVAL_DNA__FEATURE_H
/* These are macros for assembling an executable out of an explicitly-listed
* subset of "features". A feature is an object file (.o file) that contains
* the entire implementation of the feature, and is optional, ie, can be
* omitted from an executable without breaking the build.
*
* In Serval DNA, features are joined up with their infrastructure using
* linkage sections; see "sections.h" for more details.
*
* For example, a source file can add its own static function to the list of
* all URL path-to-function mappings for the HTTPD server using
* DECLARE_HANDLER() macro defined in "httpd.h". There is no
* explicitly-initialised array that lists all the URL paths; the array is
* constructed implicitly by the linker when it assembles the "httpd" section.
* Simply including the relevant object files in the link brings their
* functions into the array.
*
* Features are also used to add commands to the CLI interface and to add
* port-number handlers to the MDP interface.
*
* In order to build an executable from libservald.a, the executable needs a
* way to specify which optional features it wishes to link in, otherwise they
* will be omitted from the build, and as a result it will offer few or no CLI
* commands, no MDP services, and no HTTP services.
*
* Each source file that implements a feature must contain a DEFINE_FEATURE()
* macro, with the name of the feature as its argument.
*
* Every executable that links against libservald.a must contain a source file
* that invokes the USE_FEATURE() macro once for every defined feature it
* wishes to link in. This is typically done inside the main() function, but
* may be done within any function that is guaranteed to be included in the
* link.
*/
#define DEFINE_FEATURE(name) \
void _serval_feature__ ## name () {} \
#define USE_FEATURE(name) \
do { \
extern void _serval_feature__ ## name (); \
_serval_feature__ ## name (); \
} while (0)
#endif // __SERVAL_DNA__FEATURE_H

View File

@ -21,7 +21,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <assert.h>
#include "jni_common.h"
#include "server.h"
#include "serval.h"
#include "serval.h" // for mdp_loopback_port
#include "keyring.h"
#include "conf.h"
#include "instance.h"

207
keyring.c
View File

@ -23,17 +23,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "conf.h"
#include "constants.h"
#include "overlay_buffer.h"
#include "overlay_address.h"
#include "crypto.h"
#include "overlay_interface.h"
#include "overlay_packet.h"
#include "overlay_buffer.h"
#include "keyring.h"
#include "dataformats.h"
#include "str.h"
#include "mem.h"
#include "rotbuf.h"
#include "server.h"
#include "route_link.h"
static keyring_file *keyring_open_or_create(const char *path, int writeable);
@ -1740,76 +1737,6 @@ int keyring_sign_message(struct keyring_identity *identity, unsigned char *conte
return 0;
}
static int keyring_store_id(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
if (header->source->id_valid){
DEBUGF(keyring, "Ignoring SID:SAS mapping for %s, already have one", alloca_tohex_sid_t(header->source->sid));
return 0;
}
size_t len = ob_remaining(payload);
DEBUGF(keyring, "Received SID:SAS mapping, %zd bytes", len);
if (ob_remaining(payload) < IDENTITY_SIZE + crypto_sign_BYTES)
return WHY("Truncated key mapping announcement?");
const uint8_t *id_public = ob_get_bytes_ptr(payload, IDENTITY_SIZE);
const uint8_t *compactsignature = ob_get_bytes_ptr(payload, crypto_sign_BYTES);
if (crypto_sign_verify_detached(compactsignature, header->source->sid.binary, SID_SIZE, id_public))
return WHY("SID:SAS mapping verification signature does not verify");
// test if the signing key can be used to derive the sid
sid_t sid;
if (crypto_sign_ed25519_pk_to_curve25519(sid.binary, id_public)==0
&& memcmp(&sid, &header->source->sid, sizeof sid) == 0)
header->source->id_combined=1;
/* now store it */
bcopy(id_public, &header->source->id_public, IDENTITY_SIZE);
header->source->id_valid=1;
header->source->id_last_request=-1;
DEBUGF(keyring, "Stored SID:SAS mapping, SID=%s to SAS=%s",
alloca_tohex_sid_t(header->source->sid),
alloca_tohex_identity_t(&header->source->id_public)
);
return 0;
}
static int keyring_respond_id(struct internal_mdp_header *header)
{
keyring_identity *id = header->destination->identity;
/* It's a request, so find the SAS for the SID the request was addressed to,
use that to sign that SID, and then return it in an authcrypted frame. */
struct internal_mdp_header response;
bzero(&response, sizeof response);
mdp_init_response(header, &response);
uint8_t buff[MDP_MTU];
struct overlay_buffer *response_payload = ob_static(buff, sizeof buff);
ob_limitsize(response_payload, sizeof buff);
ob_append_byte(response_payload, KEYTYPE_CRYPTOSIGN);
ob_append_bytes(response_payload, id->sign_keypair->public_key.binary, crypto_sign_PUBLICKEYBYTES);
uint8_t *sig = ob_append_space(response_payload, crypto_sign_BYTES);
if (crypto_sign_detached(sig, NULL, header->destination->sid.binary, SID_SIZE, id->sign_keypair->binary))
return WHY("crypto_sign() failed");
DEBUGF(keyring, "Sending SID:SAS mapping, %zd bytes, %s:%"PRImdp_port_t" -> %s:%"PRImdp_port_t,
ob_position(response_payload),
alloca_tohex_sid_t(header->destination->sid), header->destination_port,
alloca_tohex_sid_t(header->source->sid), header->source_port
);
ob_flip(response_payload);
int ret = overlay_send_frame(&response, response_payload);
ob_free(response_payload);
return ret;
}
// someone else is claiming to be me on this network
// politely request that they release my identity
int keyring_send_unlock(struct subscriber *subscriber)
@ -1846,138 +1773,6 @@ int keyring_send_unlock(struct subscriber *subscriber)
return ret;
}
static int keyring_send_challenge(struct subscriber *source, struct subscriber *dest)
{
struct internal_mdp_header header;
bzero(&header, sizeof header);
header.source = source;
header.destination = dest;
header.source_port = MDP_PORT_KEYMAPREQUEST;
header.destination_port = MDP_PORT_KEYMAPREQUEST;
header.qos = OQ_MESH_MANAGEMENT;
time_ms_t now = gettime_ms();
struct keyring_challenge *challenge = source->identity->challenge;
if (challenge && challenge->expires < now){
free(challenge);
challenge = NULL;
}
if (!challenge){
challenge = emalloc_zero(sizeof(struct keyring_challenge));
if (challenge){
// give the remote party 15s to respond (should this could be based on measured link latency?)
challenge->expires = now + 15000;
randombytes_buf(challenge->challenge, sizeof(challenge->challenge));
}
}
source->identity->challenge = challenge;
if (!challenge)
return -1;
struct overlay_buffer *payload = ob_new();
ob_append_byte(payload, UNLOCK_CHALLENGE);
ob_append_bytes(payload, challenge->challenge, sizeof challenge->challenge);
DEBUGF(keyring, "Sending Unlock challenge for sid %s", alloca_tohex_sid_t(source->sid));
ob_flip(payload);
int ret = overlay_send_frame(&header, payload);
ob_free(payload);
return ret;
}
static int keyring_respond_challenge(struct subscriber *subscriber, struct overlay_buffer *payload)
{
if (!subscriber->identity)
return WHY("Cannot unlock an identity we don't have in our keyring");
if (subscriber->reachable==REACHABLE_SELF)
return 0;
struct internal_mdp_header header;
bzero(&header, sizeof header);
header.source = get_my_subscriber();
header.destination = subscriber;
header.source_port = MDP_PORT_KEYMAPREQUEST;
header.destination_port = MDP_PORT_KEYMAPREQUEST;
header.qos = OQ_MESH_MANAGEMENT;
uint8_t buff[MDP_MTU];
struct overlay_buffer *response = ob_static(buff, sizeof buff);
ob_append_byte(response, UNLOCK_RESPONSE);
ob_append_bytes(response, ob_current_ptr(payload), ob_remaining(payload));
size_t len = ob_position(response);
if (keyring_sign_message(subscriber->identity, ob_ptr(response), sizeof(buff), &len))
return -1;
ob_append_space(response, len - ob_position(response));
DEBUGF(keyring, "Responding to Unlock challenge for sid %s", alloca_tohex_sid_t(subscriber->sid));
ob_flip(response);
int ret = overlay_send_frame(&header, response);
ob_free(response);
return ret;
}
static int keyring_process_challenge(keyring_file *k, struct subscriber *subscriber, struct overlay_buffer *payload)
{
int ret=-1;
time_ms_t now = gettime_ms();
struct keyring_challenge *challenge = subscriber->identity->challenge;
if (challenge){
subscriber->identity->challenge = NULL;
size_t len = ob_remaining(payload)+1;
// verify that the payload was signed by our key and contains the same challenge bytes that we sent
// TODO allow for signing the challenge bytes without sending them twice?
if (challenge->expires >= now
&& crypto_verify_message(subscriber, ob_current_ptr(payload) -1, &len) == 0
&& len - 1 == sizeof(challenge->challenge)
&& memcmp(ob_current_ptr(payload), challenge->challenge, sizeof(challenge->challenge)) == 0){
keyring_release_subscriber(k, &subscriber->sid);
ret=0;
}else{
WHY("Challenge failed");
}
free(challenge);
}
return ret;
}
DEFINE_BINDING(MDP_PORT_KEYMAPREQUEST, keyring_mapping_request);
static int keyring_mapping_request(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
/* The authcryption of the MDP frame proves that the SAS key is owned by the
owner of the SID, and so is absolutely compulsory. */
if (header->crypt_flags&(MDP_NOCRYPT|MDP_NOSIGN))
return WHY("mapping requests must be performed under authcryption");
switch(ob_get(payload)){
case KEYTYPE_CRYPTOSIGN:
if (ob_remaining(payload)==0)
return keyring_respond_id(header);
return keyring_store_id(header, payload);
break;
case UNLOCK_REQUEST:
{
size_t len = ob_remaining(payload) +1;
if (crypto_verify_message(header->destination, ob_current_ptr(payload) -1, &len))
return WHY("Signature check failed");
}
return keyring_send_challenge(header->destination, header->source);
case UNLOCK_CHALLENGE:
return keyring_respond_challenge(header->source, payload);
case UNLOCK_RESPONSE:
return keyring_process_challenge(keyring, header->destination, payload);
}
return WHY("Not implemented");
}
int keyring_send_identity_request(struct subscriber *subscriber){
if (subscriber->id_valid)
return 0;

View File

@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef __SERVAL_DNA__KEYRING_H
#define __SERVAL_DNA__KEYRING_H
#include "serval_types.h" // for sid_t
#include "os.h" // for time_ms_t
struct cli_parsed;
#include "xprintf.h"

View File

@ -29,6 +29,8 @@
#include "commandline.h"
#include "keyring.h"
DEFINE_FEATURE(cli_keyring);
DEFINE_CMD(app_keyring_create, 0,
"Create a new keyring file.",
"keyring","create");

View File

@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "keyring.h"
#include "strbuf_helpers.h"
DEFINE_FEATURE(http_rest_keyring);
#define keyring_TOKEN_STRLEN (BASE64_ENCODED_LEN(sizeof(rhizome_bid_t) + sizeof(uint64_t)))
#define alloca_keyring_token(bid, offset) keyring_ token_to_str(alloca(keyring_TOKEN_STRLEN + 1), (bid), (offset))

12
log.c
View File

@ -34,7 +34,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <dirent.h>
#include <assert.h>
#include "serval.h"
#include "version_servald.h"
#include "instance.h"
#include "log.h"
#include "net.h"
#include "os.h"
@ -102,11 +103,6 @@ static time_t _log_file_start_time;
static char _log_file_buf[8192];
static struct strbuf _log_file_strbuf = STRUCT_STRBUF_EMPTY;
/* The log context is a string that can be set as a prefix to all subsequent log messages.
*/
static char _log_context[16];
struct strbuf log_context = STRUCT_STRBUF_INIT_STATIC(_log_context);
#ifdef ANDROID
/* Static variables for sending log output to the Android log.
*
@ -227,9 +223,9 @@ static void _log_prefix_context(_log_iterator *it)
xprintf(it->xpf, "%s.%03u ", buf, (unsigned int)it->tv.tv_usec / 1000);
}
}
if (_log_context[0]) {
if (strbuf_len(&log_context)) {
xputs("[", it->xpf);
xputs(_log_context, it->xpf);
xputs(strbuf_str(&log_context), it->xpf);
xputs("] ", it->xpf);
}
}

42
log_cli.c Normal file
View File

@ -0,0 +1,42 @@
/*
Serval DNA logging
Copyright (C) 2014-2015 Serval Project Inc.
Copyright (C) 2016 Flinders University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "feature.h"
#include "commandline.h"
#include "log.h"
#include "conf.h" // for IF_DEBUG()
DEFINE_FEATURE(cli_log);
DEFINE_CMD(app_log, CLIFLAG_PERMISSIVE_CONFIG,
"Log the supplied message at given level.",
"log","error|warn|hint|info|debug","<message>");
static int app_log(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
{
DEBUG_cli_parsed(verbose, parsed);
assert(parsed->argc == 3);
const char *lvl = parsed->args[1];
const char *msg = parsed->args[2];
int level = string_to_log_level(lvl);
if (level == LOG_LEVEL_INVALID)
return WHYF("invalid log level: %s", lvl);
logMessage(level, __NOWHERE__, "%s", msg);
return 0;
}

View File

@ -11,6 +11,8 @@
#include "str.h"
#include "numeric_str.h"
DEFINE_FEATURE(cli_meshms);
// output the list of existing conversations for a given local identity
DEFINE_CMD(app_meshms_conversations, 0,
"List MeshMS threads that include <sid>",

View File

@ -25,6 +25,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "base64.h"
#include "strbuf_helpers.h"
DEFINE_FEATURE(http_rest_meshms);
DECLARE_HANDLER("/restful/meshms/", restful_meshms_);
static void on_rhizome_bundle_added(httpd_request *r, rhizome_manifest *m);

View File

@ -32,7 +32,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "monitor-client.h"
#include "commandline.h"
int remote_print(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *UNUSED(context))
DEFINE_FEATURE(cli_monitor);
static int remote_print(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *UNUSED(context))
{
int i;
printf("%s",cmd);

View File

@ -561,6 +561,8 @@ void sigQuit(int UNUSED(signal))
proxy_state->quit=1;
}
DEFINE_FEATURE(cli_msp_proxy);
DEFINE_CMD(app_msp_connection, 0,
"Listen for incoming connections",
"msp", "listen", "[--once]", "[--forward=<local_port>]", "[--service=<service_name>]", "<port>");

View File

@ -34,6 +34,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "uri.h"
#include "overlay_buffer.h"
DEFINE_FEATURE(cli_network);
DEFINE_CMD(app_mdp_ping, 0,
"Attempts to ping specified node via Mesh Datagram Protocol (MDP).",
"mdp","ping","[--interval=<ms>]","[--timeout=<seconds>]","[--wait-for-duplicates]",

View File

@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define __SERVAL_DNA__OVERLAY_ADDRESS_H
#include "constants.h"
#include "serval_types.h" // for sid_t
#include "os.h" // for time_ms_t
#include "socket.h"
#include "nibble_tree.h"

View File

@ -20,6 +20,10 @@
#ifndef __SERVAL_DNA___OVERLAY_BUFFER_H
#define __SERVAL_DNA___OVERLAY_BUFFER_H
#include <sys/types.h> // for size_t
#include <stdint.h>
#include "whence.h"
struct overlay_buffer {
unsigned char *bytes;

View File

@ -1,5 +1,6 @@
/*
Serval DNA MDP overlay network link tracking
Copyright (C) 2016 Flinders University
Copyright (C) 2012-2013 Serval Project Inc.
Copyright (C) 2010-2012 Paul Gardner-Stephen
@ -79,7 +80,7 @@ int set_reachable(struct subscriber *subscriber,
return 1;
}
int resolve_name(const char *name, struct in_addr *addr){
static int resolve_name(const char *name, struct in_addr *addr){
// TODO this can block, move to worker thread.
IN();
int ret=0;
@ -139,32 +140,6 @@ struct network_destination *load_subscriber_address(struct subscriber *subscribe
return create_unicast_destination(&addr, interface);
}
/* Collection of unicast echo responses to detect working links */
DEFINE_BINDING(MDP_PORT_PROBE, overlay_mdp_service_probe);
static int overlay_mdp_service_probe(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
IN();
if (header->source_port!=MDP_PORT_ECHO){
WARN("Probe packets should be returned from remote echo port");
RETURN(-1);
}
DEBUGF(overlayrouting, "Received probe response from %s", alloca_tohex_sid_t(header->source->sid));
if (header->source->reachable == REACHABLE_SELF)
RETURN(0);
uint8_t interface = ob_get(payload);
struct socket_address addr;
addr.addrlen = ob_remaining(payload);
if (addr.addrlen > sizeof(addr.store))
RETURN(WHY("Badly formatted probe packet"));
ob_get_bytes(payload, (unsigned char*)&addr.addr, addr.addrlen);
RETURN(link_unicast_ack(header->source, &overlay_interfaces[interface], &addr));
OUT();
}
int overlay_send_probe(struct subscriber *peer, struct network_destination *destination, int queue){
time_ms_t now = gettime_ms();
@ -207,95 +182,6 @@ int overlay_send_probe(struct subscriber *peer, struct network_destination *dest
return 0;
}
// append the address of a unicast link into a packet buffer
static void overlay_append_unicast_address(struct subscriber *subscriber, struct overlay_buffer *buff)
{
if ( subscriber->destination
&& subscriber->destination->unicast
&& subscriber->destination->address.addr.sa_family==AF_INET
) {
overlay_address_append(NULL, buff, subscriber);
ob_append_ui32(buff, subscriber->destination->address.inet.sin_addr.s_addr);
ob_append_ui16(buff, subscriber->destination->address.inet.sin_port);
DEBUGF(overlayrouting, "Added STUN info for %s", alloca_tohex_sid_t(subscriber->sid));
}else{
DEBUGF(overlayrouting, "Unable to give address of %s, %d", alloca_tohex_sid_t(subscriber->sid),subscriber->reachable);
}
}
DEFINE_BINDING(MDP_PORT_STUNREQ, overlay_mdp_service_stun_req);
static int overlay_mdp_service_stun_req(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
DEBUGF(overlayrouting, "Processing STUN request from %s", alloca_tohex_sid_t(header->source->sid));
struct internal_mdp_header reply;
bzero(&reply, sizeof reply);
mdp_init_response(header, &reply);
reply.qos = OQ_MESH_MANAGEMENT;
struct overlay_buffer *replypayload = ob_new();
ob_limitsize(replypayload, MDP_MTU);
ob_checkpoint(replypayload);
while (ob_remaining(payload) > 0) {
struct subscriber *subscriber=NULL;
if (overlay_address_parse(NULL, payload, &subscriber))
break;
if (!subscriber){
DEBUGF(overlayrouting, "Unknown subscriber");
continue;
}
overlay_append_unicast_address(subscriber, replypayload);
if (ob_overrun(payload))
break;
ob_checkpoint(replypayload);
}
ob_rewind(replypayload);
if (ob_position(replypayload)){
DEBUGF(overlayrouting, "Sending reply");
ob_flip(replypayload);
overlay_send_frame(&reply, replypayload);
}
ob_free(replypayload);
return 0;
}
DEFINE_BINDING(MDP_PORT_STUN, overlay_mdp_service_stun);
static int overlay_mdp_service_stun(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
DEBUGF(overlayrouting, "Processing STUN info from %s", alloca_tohex_sid_t(header->source->sid));
while(ob_remaining(payload)>0){
struct subscriber *subscriber=NULL;
// TODO explain addresses, link expiry time, resolve differences between addresses...
if (overlay_address_parse(NULL, payload, &subscriber)){
break;
}
struct socket_address addr;
addr.addrlen = sizeof(addr.inet);
addr.inet.sin_family = AF_INET;
addr.inet.sin_addr.s_addr = ob_get_ui32(payload);
addr.inet.sin_port = ob_get_ui16(payload);
if (!subscriber || (subscriber->reachable&REACHABLE_DIRECT))
continue;
// only trust stun responses from our directory service or about the packet sender.
if (directory_service == header->source || subscriber == header->source){
struct network_destination *destination = create_unicast_destination(&addr, NULL);
if (destination){
overlay_send_probe(subscriber, destination, OQ_MESH_MANAGEMENT);
release_destination_ref(destination);
}
}
}
return 0;
}
int overlay_send_stun_request(struct subscriber *server, struct subscriber *request){
// don't bother with a stun request if the peer is already reachable directly
if (request->reachable&REACHABLE_DIRECT)

86
overlay_mdp_dnalookup.c Normal file
View File

@ -0,0 +1,86 @@
/*
Serval DNA MDP lookup service
Copyright (C) 2016 Flinders University
Copyright (C) 2010-2015 Serval Project Inc.
Copyright (C) 2010-2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
#include "conf.h"
#include "debug.h"
#include "overlay_buffer.h"
DEFINE_BINDING(MDP_PORT_DNALOOKUP, overlay_mdp_service_dnalookup);
static int overlay_mdp_service_dnalookup(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
IN();
keyring_iterator it;
keyring_iterator_start(keyring, &it);
char did[64+1];
int pll=ob_remaining(payload);
if (pll>64) pll=64;
/* get did from the packet */
if (pll<1)
RETURN(WHY("Empty DID in DNA resolution request"));
ob_get_bytes(payload, (unsigned char *)did, pll);
did[pll]=0;
DEBUG(mdprequests, "MDP_PORT_DNALOOKUP");
int results=0;
while(keyring_find_did(&it, did))
{
/* package DID and Name into reply (we include the DID because
it could be a wild-card DID search, but the SID is implied
in the source address of our reply). */
if (it.keypair->private_key_len > DID_MAXSIZE)
/* skip excessively long DID records */
continue;
struct subscriber *subscriber = it.identity->subscriber;
const char *unpackedDid = (const char *) it.keypair->private_key;
const char *name = (const char *)it.keypair->public_key;
// URI is sid://SIDHEX/DID
strbuf b = strbuf_alloca(SID_STRLEN + DID_MAXSIZE + 10);
strbuf_puts(b, "sid://");
strbuf_tohex(b, SID_STRLEN, subscriber->sid.binary);
strbuf_puts(b, "/local/");
strbuf_puts(b, unpackedDid);
overlay_mdp_dnalookup_reply(header->source, header->source_port, subscriber, strbuf_str(b), unpackedDid, name);
results++;
}
if (!results) {
/* No local results, so see if servald has been configured to use
a DNA-helper that can provide additional mappings. This provides
a generalised interface for resolving telephone numbers into URIs.
The first use will be for resolving DIDs to SIP addresses for
OpenBTS boxes run by the OTI/Commotion project.
The helper is run asynchronously, and the replies will be delivered
when results become available, so this function will return
immediately, so as not to cause blockages and delays in servald.
*/
dna_helper_enqueue(header->source, header->source_port, did);
monitor_tell_formatted(MONITOR_DNAHELPER, "LOOKUP:%s:%d:%s\n",
alloca_tohex_sid_t(header->source->sid), header->source_port,
did);
}
RETURN(0);
}

42
overlay_mdp_echo.c Normal file
View File

@ -0,0 +1,42 @@
/*
Serval DNA MDP echo service
Copyright (C) 2016 Flinders University
Copyright (C) 2012-2015 Serval Project Inc.
Copyright (C) 2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mdp_client.h"
#include "overlay_packet.h"
#include "fdqueue.h"
DEFINE_BINDING(MDP_PORT_ECHO, overlay_mdp_service_echo);
static int overlay_mdp_service_echo(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
IN();
if (header->source_port == MDP_PORT_ECHO)
RETURN(WHY("Prevented infinite echo loop"));
struct internal_mdp_header response_header;
bzero(&response_header, sizeof response_header);
mdp_init_response(header, &response_header);
// keep all defaults
RETURN(overlay_send_frame(&response_header, payload));
OUT();
}

229
overlay_mdp_keymaprequest.c Normal file
View File

@ -0,0 +1,229 @@
/*
Serval DNA keyring MDP key map request
Copyright (C) 2016 Flinders University
Copyright (C) 2010-2015 Serval Project Inc.
Copyright (C) 2010-2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "keyring.h"
#include "conf.h"
#include "debug.h"
#include "overlay_buffer.h"
#include "crypto.h"
#include "mem.h"
static int keyring_respond_id(struct internal_mdp_header *header)
{
keyring_identity *id = header->destination->identity;
/* It's a request, so find the SAS for the SID the request was addressed to,
use that to sign that SID, and then return it in an authcrypted frame. */
struct internal_mdp_header response;
bzero(&response, sizeof response);
mdp_init_response(header, &response);
uint8_t buff[MDP_MTU];
struct overlay_buffer *response_payload = ob_static(buff, sizeof buff);
ob_limitsize(response_payload, sizeof buff);
ob_append_byte(response_payload, KEYTYPE_CRYPTOSIGN);
ob_append_bytes(response_payload, id->sign_keypair->public_key.binary, crypto_sign_PUBLICKEYBYTES);
uint8_t *sig = ob_append_space(response_payload, crypto_sign_BYTES);
if (crypto_sign_detached(sig, NULL, header->destination->sid.binary, SID_SIZE, id->sign_keypair->binary))
return WHY("crypto_sign() failed");
DEBUGF(keyring, "Sending SID:SAS mapping, %zd bytes, %s:%"PRImdp_port_t" -> %s:%"PRImdp_port_t,
ob_position(response_payload),
alloca_tohex_sid_t(header->destination->sid), header->destination_port,
alloca_tohex_sid_t(header->source->sid), header->source_port
);
ob_flip(response_payload);
int ret = overlay_send_frame(&response, response_payload);
ob_free(response_payload);
return ret;
}
static int keyring_store_id(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
if (header->source->id_valid){
DEBUGF(keyring, "Ignoring SID:SAS mapping for %s, already have one", alloca_tohex_sid_t(header->source->sid));
return 0;
}
size_t len = ob_remaining(payload);
DEBUGF(keyring, "Received SID:SAS mapping, %zd bytes", len);
if (ob_remaining(payload) < IDENTITY_SIZE + crypto_sign_BYTES)
return WHY("Truncated key mapping announcement?");
const uint8_t *id_public = ob_get_bytes_ptr(payload, IDENTITY_SIZE);
const uint8_t *compactsignature = ob_get_bytes_ptr(payload, crypto_sign_BYTES);
if (crypto_sign_verify_detached(compactsignature, header->source->sid.binary, SID_SIZE, id_public))
return WHY("SID:SAS mapping verification signature does not verify");
// test if the signing key can be used to derive the sid
sid_t sid;
if (crypto_sign_ed25519_pk_to_curve25519(sid.binary, id_public)==0
&& memcmp(&sid, &header->source->sid, sizeof sid) == 0)
header->source->id_combined=1;
/* now store it */
bcopy(id_public, &header->source->id_public, IDENTITY_SIZE);
header->source->id_valid=1;
header->source->id_last_request=-1;
DEBUGF(keyring, "Stored SID:SAS mapping, SID=%s to SAS=%s",
alloca_tohex_sid_t(header->source->sid),
alloca_tohex_identity_t(&header->source->id_public)
);
return 0;
}
static int keyring_send_challenge(struct subscriber *source, struct subscriber *dest)
{
struct internal_mdp_header header;
bzero(&header, sizeof header);
header.source = source;
header.destination = dest;
header.source_port = MDP_PORT_KEYMAPREQUEST;
header.destination_port = MDP_PORT_KEYMAPREQUEST;
header.qos = OQ_MESH_MANAGEMENT;
time_ms_t now = gettime_ms();
struct keyring_challenge *challenge = source->identity->challenge;
if (challenge && challenge->expires < now){
free(challenge);
challenge = NULL;
}
if (!challenge){
challenge = emalloc_zero(sizeof(struct keyring_challenge));
if (challenge){
// give the remote party 15s to respond (should this could be based on measured link latency?)
challenge->expires = now + 15000;
randombytes_buf(challenge->challenge, sizeof(challenge->challenge));
}
}
source->identity->challenge = challenge;
if (!challenge)
return -1;
struct overlay_buffer *payload = ob_new();
ob_append_byte(payload, UNLOCK_CHALLENGE);
ob_append_bytes(payload, challenge->challenge, sizeof challenge->challenge);
DEBUGF(keyring, "Sending Unlock challenge for sid %s", alloca_tohex_sid_t(source->sid));
ob_flip(payload);
int ret = overlay_send_frame(&header, payload);
ob_free(payload);
return ret;
}
static int keyring_respond_challenge(struct subscriber *subscriber, struct overlay_buffer *payload)
{
if (!subscriber->identity)
return WHY("Cannot unlock an identity we don't have in our keyring");
if (subscriber->reachable==REACHABLE_SELF)
return 0;
struct internal_mdp_header header;
bzero(&header, sizeof header);
header.source = get_my_subscriber();
header.destination = subscriber;
header.source_port = MDP_PORT_KEYMAPREQUEST;
header.destination_port = MDP_PORT_KEYMAPREQUEST;
header.qos = OQ_MESH_MANAGEMENT;
uint8_t buff[MDP_MTU];
struct overlay_buffer *response = ob_static(buff, sizeof buff);
ob_append_byte(response, UNLOCK_RESPONSE);
ob_append_bytes(response, ob_current_ptr(payload), ob_remaining(payload));
size_t len = ob_position(response);
if (keyring_sign_message(subscriber->identity, ob_ptr(response), sizeof(buff), &len))
return -1;
ob_append_space(response, len - ob_position(response));
DEBUGF(keyring, "Responding to Unlock challenge for sid %s", alloca_tohex_sid_t(subscriber->sid));
ob_flip(response);
int ret = overlay_send_frame(&header, response);
ob_free(response);
return ret;
}
static int keyring_process_challenge(keyring_file *k, struct subscriber *subscriber, struct overlay_buffer *payload)
{
int ret=-1;
time_ms_t now = gettime_ms();
struct keyring_challenge *challenge = subscriber->identity->challenge;
if (challenge){
subscriber->identity->challenge = NULL;
size_t len = ob_remaining(payload)+1;
// verify that the payload was signed by our key and contains the same challenge bytes that we sent
// TODO allow for signing the challenge bytes without sending them twice?
if (challenge->expires >= now
&& crypto_verify_message(subscriber, ob_current_ptr(payload) -1, &len) == 0
&& len - 1 == sizeof(challenge->challenge)
&& memcmp(ob_current_ptr(payload), challenge->challenge, sizeof(challenge->challenge)) == 0){
keyring_release_subscriber(k, &subscriber->sid);
ret=0;
}else{
WHY("Challenge failed");
}
free(challenge);
}
return ret;
}
DEFINE_BINDING(MDP_PORT_KEYMAPREQUEST, keyring_mapping_request);
static int keyring_mapping_request(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
/* The authcryption of the MDP frame proves that the SAS key is owned by the
owner of the SID, and so is absolutely compulsory. */
if (header->crypt_flags&(MDP_NOCRYPT|MDP_NOSIGN))
return WHY("mapping requests must be performed under authcryption");
switch(ob_get(payload)){
case KEYTYPE_CRYPTOSIGN:
if (ob_remaining(payload)==0)
return keyring_respond_id(header);
return keyring_store_id(header, payload);
break;
case UNLOCK_REQUEST:
{
size_t len = ob_remaining(payload) +1;
if (crypto_verify_message(header->destination, ob_current_ptr(payload) -1, &len))
return WHY("Signature check failed");
}
return keyring_send_challenge(header->destination, header->source);
case UNLOCK_CHALLENGE:
return keyring_respond_challenge(header->source, payload);
case UNLOCK_RESPONSE:
return keyring_process_challenge(keyring, header->destination, payload);
}
return WHY("Not implemented");
}

185
overlay_mdp_rhizome.c Normal file
View File

@ -0,0 +1,185 @@
/*
Serval DNA basic MDP services
Copyright (C) 2016 Flinders University
Copyright (C) 2010-2015 Serval Project Inc.
Copyright (C) 2010-2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
#include "conf.h"
#include "overlay_buffer.h"
#include "rhizome.h"
#include "mdp_client.h"
static int rhizome_mdp_send_block(struct subscriber *dest, const rhizome_bid_t *bid, uint64_t version, uint64_t fileOffset, uint32_t bitmap, uint16_t blockLength)
{
IN();
if (!is_rhizome_mdp_server_running())
RETURN(-1);
if (blockLength<=0 || blockLength>1024)
RETURN(WHYF("Invalid block length %d", blockLength));
DEBUGF(rhizome_tx, "Requested blocks for bid=%s, ver=%"PRIu64" @%"PRIx64" bitmap %x", alloca_tohex_rhizome_bid_t(*bid), version, fileOffset, bitmap);
struct internal_mdp_header header;
bzero(&header, sizeof header);
uint8_t buff[MDP_MTU];
struct overlay_buffer *payload = ob_static(buff, sizeof(buff));
// Reply is broadcast, so we cannot authcrypt, and signing is too time consuming
// for low devices. The result is that an attacker can prevent rhizome transfers
// if they want to by injecting fake blocks. The alternative is to not broadcast
// back replies, and then we can authcrypt.
// multiple receivers starting at different times, we really need merkle-tree hashing.
// so multiple receivers is not realistic for now. So use non-broadcast unicode
// for now would seem the safest. But that would stop us from allowing multiple
// receivers in the special case where additional nodes begin listening in from the
// beginning.
header.crypt_flags = MDP_FLAG_NO_CRYPT | MDP_FLAG_NO_SIGN;
header.source = get_my_subscriber();
header.source_port = MDP_PORT_RHIZOME_RESPONSE;
if (dest && (dest->reachable==REACHABLE_UNICAST || dest->reachable==REACHABLE_INDIRECT)){
// if we get a request from a peer that we can only talk to via unicast, send data via unicast too.
header.destination = dest;
}else{
// send replies to broadcast so that others can hear blocks and record them
// (not that preemptive listening is implemented yet).
header.ttl = 1;
}
header.destination_port = MDP_PORT_RHIZOME_RESPONSE;
header.qos = OQ_OPPORTUNISTIC;
int i;
for(i=0;i<32;i++){
if (bitmap&(1u<<(31-i)))
continue;
if (overlay_queue_remaining(header.qos) < 10)
break;
// calculate and set offset of block
uint64_t offset = fileOffset+i*blockLength;
ob_clear(payload);
ob_append_byte(payload, 'B'); // contains blocks
// include 16 bytes of BID prefix for identification
ob_append_bytes(payload, bid->binary, 16);
// and version of manifest (in the correct byte order)
ob_append_ui64_rv(payload, version);
ob_append_ui64_rv(payload, offset);
ssize_t bytes_read = rhizome_read_cached(bid, version, gettime_ms()+5000, offset, ob_current_ptr(payload), blockLength);
if (bytes_read<=0)
break;
ob_append_space(payload, bytes_read);
// Mark the last block of the file, if required
if ((size_t)bytes_read < blockLength)
ob_set(payload, 0, 'T');
// send packet
ob_flip(payload);
if (overlay_send_frame(&header, payload))
break;
}
ob_free(payload);
RETURN(0);
OUT();
}
DEFINE_BINDING(MDP_PORT_RHIZOME_REQUEST, overlay_mdp_service_rhizomerequest);
static int overlay_mdp_service_rhizomerequest(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
const rhizome_bid_t *bidp = (const rhizome_bid_t *) ob_get_bytes_ptr(payload, sizeof bidp->binary);
// Note, was originally built using read_uint64 which has reverse byte order of ob_get_ui64
uint64_t version = ob_get_ui64_rv(payload);
uint64_t fileOffset = ob_get_ui64_rv(payload);
uint32_t bitmap = ob_get_ui32_rv(payload);
uint16_t blockLength = ob_get_ui16_rv(payload);
if (ob_overrun(payload))
return -1;
return rhizome_mdp_send_block(header->source, bidp, version, fileOffset, bitmap, blockLength);
}
DEFINE_BINDING(MDP_PORT_RHIZOME_RESPONSE, overlay_mdp_service_rhizomeresponse);
static int overlay_mdp_service_rhizomeresponse(struct internal_mdp_header *UNUSED(header), struct overlay_buffer *payload)
{
IN();
int type=ob_get(payload);
DEBUGF(rhizome_mdp_rx, "Received Rhizome over MDP block, type=%02x",type);
switch (type) {
case 'B': /* data block */
case 'T': /* terminal data block */
{
unsigned char *bidprefix=ob_get_bytes_ptr(payload, 16);
uint64_t version=ob_get_ui64_rv(payload);
uint64_t offset=ob_get_ui64_rv(payload);
if (ob_overrun(payload))
RETURN(WHYF("Payload too short"));
size_t count = ob_remaining(payload);
unsigned char *bytes=ob_current_ptr(payload);
DEBUGF(rhizome_mdp_rx, "bidprefix=%02x%02x%02x%02x*, offset=%"PRId64", count=%zu",
bidprefix[0],bidprefix[1],bidprefix[2],bidprefix[3],offset,count);
/* Now see if there is a slot that matches. If so, then
see if the bytes are in the window, and write them.
If there is not matching slot, then consider setting
a slot to capture this files as it is being requested
by someone else.
*/
rhizome_received_content(bidprefix,version,offset, count, bytes);
RETURN(0);
}
break;
}
RETURN(-1);
OUT();
}
DEFINE_BINDING(MDP_PORT_RHIZOME_MANIFEST_REQUEST, overlay_mdp_service_manifest_requests);
static int overlay_mdp_service_manifest_requests(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
while (ob_remaining(payload)) {
const unsigned char *bar = ob_get_bytes_ptr(payload, RHIZOME_BAR_BYTES);
if (!bar)
break;
rhizome_manifest *m = rhizome_new_manifest();
if (!m)
return WHY("Unable to allocate manifest");
if (rhizome_retrieve_manifest_by_prefix(&bar[RHIZOME_BAR_PREFIX_OFFSET], RHIZOME_BAR_PREFIX_BYTES, m)==RHIZOME_BUNDLE_STATUS_SAME){
rhizome_advertise_manifest(header->source, m);
// pre-emptively send the payload if it will fit in a single packet
if (m->filesize > 0 && m->filesize <= 1024)
rhizome_mdp_send_block(header->source, &m->keypair.public_key, m->version, 0, 0, m->filesize);
}
rhizome_manifest_free(m);
}
return 0;
}

View File

@ -1,383 +0,0 @@
/*
Copyright (C) 2010-2012 Paul Gardner-Stephen
Copyright (C) 2010-2013 Serval Project Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <sys/stat.h>
#include "serval.h"
#include "conf.h"
#include "str.h"
#include "strbuf.h"
#include "overlay_buffer.h"
#include "overlay_address.h"
#include "overlay_packet.h"
#include "mdp_client.h"
#include "rhizome.h"
#include "crypto.h"
#include "log.h"
#include "debug.h"
#include "keyring.h"
#include "dataformats.h"
#include "route_link.h"
int rhizome_mdp_send_block(struct subscriber *dest, const rhizome_bid_t *bid, uint64_t version, uint64_t fileOffset, uint32_t bitmap, uint16_t blockLength)
{
IN();
if (!is_rhizome_mdp_server_running())
RETURN(-1);
if (blockLength<=0 || blockLength>1024)
RETURN(WHYF("Invalid block length %d", blockLength));
DEBUGF(rhizome_tx, "Requested blocks for bid=%s, ver=%"PRIu64" @%"PRIx64" bitmap %x", alloca_tohex_rhizome_bid_t(*bid), version, fileOffset, bitmap);
struct internal_mdp_header header;
bzero(&header, sizeof header);
uint8_t buff[MDP_MTU];
struct overlay_buffer *payload = ob_static(buff, sizeof(buff));
// Reply is broadcast, so we cannot authcrypt, and signing is too time consuming
// for low devices. The result is that an attacker can prevent rhizome transfers
// if they want to by injecting fake blocks. The alternative is to not broadcast
// back replies, and then we can authcrypt.
// multiple receivers starting at different times, we really need merkle-tree hashing.
// so multiple receivers is not realistic for now. So use non-broadcast unicode
// for now would seem the safest. But that would stop us from allowing multiple
// receivers in the special case where additional nodes begin listening in from the
// beginning.
header.crypt_flags = MDP_FLAG_NO_CRYPT | MDP_FLAG_NO_SIGN;
header.source = get_my_subscriber();
header.source_port = MDP_PORT_RHIZOME_RESPONSE;
if (dest && (dest->reachable==REACHABLE_UNICAST || dest->reachable==REACHABLE_INDIRECT)){
// if we get a request from a peer that we can only talk to via unicast, send data via unicast too.
header.destination = dest;
}else{
// send replies to broadcast so that others can hear blocks and record them
// (not that preemptive listening is implemented yet).
header.ttl = 1;
}
header.destination_port = MDP_PORT_RHIZOME_RESPONSE;
header.qos = OQ_OPPORTUNISTIC;
int i;
for(i=0;i<32;i++){
if (bitmap&(1u<<(31-i)))
continue;
if (overlay_queue_remaining(header.qos) < 10)
break;
// calculate and set offset of block
uint64_t offset = fileOffset+i*blockLength;
ob_clear(payload);
ob_append_byte(payload, 'B'); // contains blocks
// include 16 bytes of BID prefix for identification
ob_append_bytes(payload, bid->binary, 16);
// and version of manifest (in the correct byte order)
ob_append_ui64_rv(payload, version);
ob_append_ui64_rv(payload, offset);
ssize_t bytes_read = rhizome_read_cached(bid, version, gettime_ms()+5000, offset, ob_current_ptr(payload), blockLength);
if (bytes_read<=0)
break;
ob_append_space(payload, bytes_read);
// Mark the last block of the file, if required
if ((size_t)bytes_read < blockLength)
ob_set(payload, 0, 'T');
// send packet
ob_flip(payload);
if (overlay_send_frame(&header, payload))
break;
}
ob_free(payload);
RETURN(0);
OUT();
}
DEFINE_BINDING(MDP_PORT_RHIZOME_REQUEST, overlay_mdp_service_rhizomerequest);
static int overlay_mdp_service_rhizomerequest(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
const rhizome_bid_t *bidp = (const rhizome_bid_t *) ob_get_bytes_ptr(payload, sizeof bidp->binary);
// Note, was originally built using read_uint64 which has reverse byte order of ob_get_ui64
uint64_t version = ob_get_ui64_rv(payload);
uint64_t fileOffset = ob_get_ui64_rv(payload);
uint32_t bitmap = ob_get_ui32_rv(payload);
uint16_t blockLength = ob_get_ui16_rv(payload);
if (ob_overrun(payload))
return -1;
return rhizome_mdp_send_block(header->source, bidp, version, fileOffset, bitmap, blockLength);
}
DEFINE_BINDING(MDP_PORT_RHIZOME_RESPONSE, overlay_mdp_service_rhizomeresponse);
static int overlay_mdp_service_rhizomeresponse(struct internal_mdp_header *UNUSED(header), struct overlay_buffer *payload)
{
IN();
int type=ob_get(payload);
DEBUGF(rhizome_mdp_rx, "Received Rhizome over MDP block, type=%02x",type);
switch (type) {
case 'B': /* data block */
case 'T': /* terminal data block */
{
unsigned char *bidprefix=ob_get_bytes_ptr(payload, 16);
uint64_t version=ob_get_ui64_rv(payload);
uint64_t offset=ob_get_ui64_rv(payload);
if (ob_overrun(payload))
RETURN(WHYF("Payload too short"));
size_t count = ob_remaining(payload);
unsigned char *bytes=ob_current_ptr(payload);
DEBUGF(rhizome_mdp_rx, "bidprefix=%02x%02x%02x%02x*, offset=%"PRId64", count=%zu",
bidprefix[0],bidprefix[1],bidprefix[2],bidprefix[3],offset,count);
/* Now see if there is a slot that matches. If so, then
see if the bytes are in the window, and write them.
If there is not matching slot, then consider setting
a slot to capture this files as it is being requested
by someone else.
*/
rhizome_received_content(bidprefix,version,offset, count, bytes);
RETURN(0);
}
break;
}
RETURN(-1);
OUT();
}
DEFINE_BINDING(MDP_PORT_DNALOOKUP, overlay_mdp_service_dnalookup);
static int overlay_mdp_service_dnalookup(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
IN();
keyring_iterator it;
keyring_iterator_start(keyring, &it);
char did[64+1];
int pll=ob_remaining(payload);
if (pll>64) pll=64;
/* get did from the packet */
if (pll<1)
RETURN(WHY("Empty DID in DNA resolution request"));
ob_get_bytes(payload, (unsigned char *)did, pll);
did[pll]=0;
DEBUG(mdprequests, "MDP_PORT_DNALOOKUP");
int results=0;
while(keyring_find_did(&it, did))
{
/* package DID and Name into reply (we include the DID because
it could be a wild-card DID search, but the SID is implied
in the source address of our reply). */
if (it.keypair->private_key_len > DID_MAXSIZE)
/* skip excessively long DID records */
continue;
struct subscriber *subscriber = it.identity->subscriber;
const char *unpackedDid = (const char *) it.keypair->private_key;
const char *name = (const char *)it.keypair->public_key;
// URI is sid://SIDHEX/DID
strbuf b = strbuf_alloca(SID_STRLEN + DID_MAXSIZE + 10);
strbuf_puts(b, "sid://");
strbuf_tohex(b, SID_STRLEN, subscriber->sid.binary);
strbuf_puts(b, "/local/");
strbuf_puts(b, unpackedDid);
overlay_mdp_dnalookup_reply(header->source, header->source_port, subscriber, strbuf_str(b), unpackedDid, name);
results++;
}
if (!results) {
/* No local results, so see if servald has been configured to use
a DNA-helper that can provide additional mappings. This provides
a generalised interface for resolving telephone numbers into URIs.
The first use will be for resolving DIDs to SIP addresses for
OpenBTS boxes run by the OTI/Commotion project.
The helper is run asynchronously, and the replies will be delivered
when results become available, so this function will return
immediately, so as not to cause blockages and delays in servald.
*/
dna_helper_enqueue(header->source, header->source_port, did);
monitor_tell_formatted(MONITOR_DNAHELPER, "LOOKUP:%s:%d:%s\n",
alloca_tohex_sid_t(header->source->sid), header->source_port,
did);
}
RETURN(0);
}
DEFINE_BINDING(MDP_PORT_ECHO, overlay_mdp_service_echo);
static int overlay_mdp_service_echo(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
IN();
if (header->source_port == MDP_PORT_ECHO)
RETURN(WHY("Prevented infinite echo loop"));
struct internal_mdp_header response_header;
bzero(&response_header, sizeof response_header);
mdp_init_response(header, &response_header);
// keep all defaults
RETURN(overlay_send_frame(&response_header, payload));
OUT();
}
/*
* Trace packets are a little weird so that they can be modified by every node
* and so they can bypass the routing table.
*
* The true source and destination addresses are encoded inside the payload
* each node that processes the packet appends their own address before forwarding it to the next hop
* if their SID is already in the packet, the next hop is chosen from the immediately preceeding SID in the list.
* otherwise the next SID is chosen based on the current routing table.
*
* In this way the packet can follow the path defined by each node's routing table
* Until the packet reaches the destination, the destination is unreachable, or the packet loops around the network
* Once any of these end states occurs, the packet attempts to travel back to the source node,
* while using the source addresses in the trace packet for guidance instead of trusting the routing table.
*
* It is hoped that this information can be useful to better understand the current network state
* in situations where a routing protocol is in development.
*/
DEFINE_BINDING(MDP_PORT_TRACE, overlay_mdp_service_trace);
static int overlay_mdp_service_trace(struct internal_mdp_header *header, struct overlay_buffer *payload){
IN();
struct overlay_buffer *next_payload = ob_new();
if (!next_payload)
RETURN(-1);
ob_append_bytes(next_payload, ob_current_ptr(payload), ob_remaining(payload));
int ret=0;
struct subscriber *src=NULL, *dst=NULL, *last=NULL;
struct decode_context context;
bzero(&context, sizeof context);
if (header->source_port == MDP_PORT_TRACE){
ret=WHYF("Invalid source port");
goto end;
}
if (overlay_address_parse(&context, payload, &src)){
ret=WHYF("Invalid source SID");
goto end;
}
if (overlay_address_parse(&context, payload, &dst)){
ret=WHYF("Invalid destination SID");
goto end;
}
if (context.flags & DECODE_FLAG_INVALID_ADDRESS){
ret=WHYF("Unknown address in trace packet");
goto end;
}
INFOF("Trace from %s to %s", alloca_tohex_sid_t(src->sid), alloca_tohex_sid_t(dst->sid));
struct internal_mdp_header next_header;
next_header = *header;
next_header.source = get_my_subscriber();
next_header.destination = NULL;
while(ob_remaining(payload)>0){
struct subscriber *trace=NULL;
if (overlay_address_parse(&context, payload, &trace)){
ret=WHYF("Invalid SID in packet payload");
goto end;
}
if (context.flags & DECODE_FLAG_INVALID_ADDRESS){
ret=WHYF("Unknown SID in packet payload");
goto end;
}
INFOF("Via %s", alloca_tohex_sid_t(trace->sid));
if (trace->reachable==REACHABLE_SELF && !next_header.destination)
// We're already in this trace, send the next packet to the node before us in the list
next_header.destination = last;
last = trace;
}
if (src->reachable==REACHABLE_SELF && last){
// it came back to us, we can send the reply to our mdp client...
next_header.destination=src;
next_header.destination_port = header->source_port;
next_header.source_port = MDP_PORT_TRACE;
}
if (!next_header.destination){
// destination is our neighbour?
if (dst->reachable & REACHABLE_DIRECT)
next_header.destination = dst;
// destination is indirect?
else if (dst->reachable & REACHABLE_INDIRECT)
next_header.destination = dst->next_hop;
// destination is not reachable or is ourselves? bounce back to the previous node or the sender.
else if (last)
next_header.destination = last;
else
next_header.destination = src;
}
INFOF("Next node is %s", alloca_tohex_sid_t(next_header.destination->sid));
// always write a full sid into the payload
next_header.source->send_full=1;
overlay_address_append(&context, next_payload, next_header.source);
if (ob_overrun(next_payload)) {
ret = WHYF("Unable to append my address to the trace");
goto end;
}
ob_flip(next_payload);
ret = overlay_send_frame(&next_header, next_payload);
end:
ob_free(next_payload);
RETURN(ret);
}
DEFINE_BINDING(MDP_PORT_RHIZOME_MANIFEST_REQUEST, overlay_mdp_service_manifest_requests);
static int overlay_mdp_service_manifest_requests(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
while (ob_remaining(payload)) {
const unsigned char *bar = ob_get_bytes_ptr(payload, RHIZOME_BAR_BYTES);
if (!bar)
break;
rhizome_manifest *m = rhizome_new_manifest();
if (!m)
return WHY("Unable to allocate manifest");
if (rhizome_retrieve_manifest_by_prefix(&bar[RHIZOME_BAR_PREFIX_OFFSET], RHIZOME_BAR_PREFIX_BYTES, m)==RHIZOME_BUNDLE_STATUS_SAME){
rhizome_advertise_manifest(header->source, m);
// pre-emptively send the payload if it will fit in a single packet
if (m->filesize > 0 && m->filesize <= 1024)
rhizome_mdp_send_block(header->source, &m->keypair.public_key, m->version, 0, 0, m->filesize);
}
rhizome_manifest_free(m);
}
return 0;
}

136
overlay_mdp_trace.c Normal file
View File

@ -0,0 +1,136 @@
/*
Serval DNA MDP trace service
Copyright (C) 2016 Flinders University
Copyright (C) 2012-2015 Serval Project Inc.
Copyright (C) 2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "overlay_buffer.h"
#include "overlay_address.h"
#include "overlay_packet.h"
#include "mdp_client.h"
#include "fdqueue.h"
#include "str.h"
/*
* Trace packets are a little weird so that they can be modified by every node
* and so they can bypass the routing table.
*
* The true source and destination addresses are encoded inside the payload
* each node that processes the packet appends their own address before forwarding it to the next hop
* if their SID is already in the packet, the next hop is chosen from the immediately preceeding SID in the list.
* otherwise the next SID is chosen based on the current routing table.
*
* In this way the packet can follow the path defined by each node's routing table
* Until the packet reaches the destination, the destination is unreachable, or the packet loops around the network
* Once any of these end states occurs, the packet attempts to travel back to the source node,
* while using the source addresses in the trace packet for guidance instead of trusting the routing table.
*
* It is hoped that this information can be useful to better understand the current network state
* in situations where a routing protocol is in development.
*/
DEFINE_BINDING(MDP_PORT_TRACE, overlay_mdp_service_trace);
static int overlay_mdp_service_trace(struct internal_mdp_header *header, struct overlay_buffer *payload){
IN();
struct overlay_buffer *next_payload = ob_new();
if (!next_payload)
RETURN(-1);
ob_append_bytes(next_payload, ob_current_ptr(payload), ob_remaining(payload));
int ret=0;
struct subscriber *src=NULL, *dst=NULL, *last=NULL;
struct decode_context context;
bzero(&context, sizeof context);
if (header->source_port == MDP_PORT_TRACE){
ret=WHYF("Invalid source port");
goto end;
}
if (overlay_address_parse(&context, payload, &src)){
ret=WHYF("Invalid source SID");
goto end;
}
if (overlay_address_parse(&context, payload, &dst)){
ret=WHYF("Invalid destination SID");
goto end;
}
if (context.flags & DECODE_FLAG_INVALID_ADDRESS){
ret=WHYF("Unknown address in trace packet");
goto end;
}
INFOF("Trace from %s to %s", alloca_tohex_sid_t(src->sid), alloca_tohex_sid_t(dst->sid));
struct internal_mdp_header next_header;
next_header = *header;
next_header.source = get_my_subscriber();
next_header.destination = NULL;
while(ob_remaining(payload)>0){
struct subscriber *trace=NULL;
if (overlay_address_parse(&context, payload, &trace)){
ret=WHYF("Invalid SID in packet payload");
goto end;
}
if (context.flags & DECODE_FLAG_INVALID_ADDRESS){
ret=WHYF("Unknown SID in packet payload");
goto end;
}
INFOF("Via %s", alloca_tohex_sid_t(trace->sid));
if (trace->reachable==REACHABLE_SELF && !next_header.destination)
// We're already in this trace, send the next packet to the node before us in the list
next_header.destination = last;
last = trace;
}
if (src->reachable==REACHABLE_SELF && last){
// it came back to us, we can send the reply to our mdp client...
next_header.destination=src;
next_header.destination_port = header->source_port;
next_header.source_port = MDP_PORT_TRACE;
}
if (!next_header.destination){
// destination is our neighbour?
if (dst->reachable & REACHABLE_DIRECT)
next_header.destination = dst;
// destination is indirect?
else if (dst->reachable & REACHABLE_INDIRECT)
next_header.destination = dst->next_hop;
// destination is not reachable or is ourselves? bounce back to the previous node or the sender.
else if (last)
next_header.destination = last;
else
next_header.destination = src;
}
INFOF("Next node is %s", alloca_tohex_sid_t(next_header.destination->sid));
// always write a full sid into the payload
next_header.source->send_full=1;
overlay_address_append(&context, next_payload, next_header.source);
if (ob_overrun(next_payload)) {
ret = WHYF("Unable to append my address to the trace");
goto end;
}
ob_flip(next_payload);
ret = overlay_send_frame(&next_header, next_payload);
end:
ob_free(next_payload);
RETURN(ret);
}

View File

@ -21,6 +21,7 @@
#define __SERVAL_DNA__OVERLAY_PACKET_H
#include "serval_types.h"
#include "feature.h"
#include "overlay_address.h"
#include "section.h"
@ -143,6 +144,7 @@ struct internal_binding{
DECLARE_SECTION(struct internal_binding, bindings);
#define DEFINE_BINDING(PORT, FUNC) \
DEFINE_FEATURE(mdp_binding_ ## PORT); \
static int FUNC(struct internal_mdp_header *, struct overlay_buffer *);\
static struct internal_binding BIND ## FUNC IN_SECTION(bindings) = { \
.port = PORT, \

54
overlay_probe.c Normal file
View File

@ -0,0 +1,54 @@
/*
Serval DNA MDP overlay network link tracking
Copyright (C) 2016 Flinders University
Copyright (C) 2012-2013 Serval Project Inc.
Copyright (C) 2010-2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
#include "conf.h"
#include "route_link.h"
#include "overlay_interface.h"
#include "overlay_buffer.h"
#include "fdqueue.h"
/* Collection of unicast echo responses to detect working links */
DEFINE_BINDING(MDP_PORT_PROBE, overlay_mdp_service_probe);
static int overlay_mdp_service_probe(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
IN();
if (header->source_port!=MDP_PORT_ECHO){
WARN("Probe packets should be returned from remote echo port");
RETURN(-1);
}
DEBUGF(overlayrouting, "Received probe response from %s", alloca_tohex_sid_t(header->source->sid));
if (header->source->reachable == REACHABLE_SELF)
RETURN(0);
uint8_t interface = ob_get(payload);
struct socket_address addr;
addr.addrlen = ob_remaining(payload);
if (addr.addrlen > sizeof(addr.store))
RETURN(WHY("Badly formatted probe packet"));
ob_get_bytes(payload, (unsigned char*)&addr.addr, addr.addrlen);
RETURN(link_unicast_ack(header->source, &overlay_interfaces[interface], &addr));
OUT();
}

60
overlay_stun.c Normal file
View File

@ -0,0 +1,60 @@
/*
Serval DNA MDP overlay network link tracking
Copyright (C) 2016 Flinders University
Copyright (C) 2012-2013 Serval Project Inc.
Copyright (C) 2010-2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
#include "conf.h"
#include "route_link.h"
#include "overlay_interface.h"
#include "overlay_buffer.h"
DEFINE_BINDING(MDP_PORT_STUN, overlay_mdp_service_stun);
static int overlay_mdp_service_stun(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
DEBUGF(overlayrouting, "Processing STUN info from %s", alloca_tohex_sid_t(header->source->sid));
while(ob_remaining(payload)>0){
struct subscriber *subscriber=NULL;
// TODO explain addresses, link expiry time, resolve differences between addresses...
if (overlay_address_parse(NULL, payload, &subscriber)){
break;
}
struct socket_address addr;
addr.addrlen = sizeof(addr.inet);
addr.inet.sin_family = AF_INET;
addr.inet.sin_addr.s_addr = ob_get_ui32(payload);
addr.inet.sin_port = ob_get_ui16(payload);
if (!subscriber || (subscriber->reachable&REACHABLE_DIRECT))
continue;
// only trust stun responses from our directory service or about the packet sender.
if (directory_service == header->source || subscriber == header->source){
struct network_destination *destination = create_unicast_destination(&addr, NULL);
if (destination){
overlay_send_probe(subscriber, destination, OQ_MESH_MANAGEMENT);
release_destination_ref(destination);
}
}
}
return 0;
}

81
overlay_stunreq.c Normal file
View File

@ -0,0 +1,81 @@
/*
Serval DNA MDP overlay network link tracking
Copyright (C) 2016 Flinders University
Copyright (C) 2012-2013 Serval Project Inc.
Copyright (C) 2010-2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
#include "conf.h"
#include "route_link.h"
#include "overlay_interface.h"
#include "overlay_buffer.h"
// append the address of a unicast link into a packet buffer
static void overlay_append_unicast_address(struct subscriber *subscriber, struct overlay_buffer *buff)
{
if ( subscriber->destination
&& subscriber->destination->unicast
&& subscriber->destination->address.addr.sa_family==AF_INET
) {
overlay_address_append(NULL, buff, subscriber);
ob_append_ui32(buff, subscriber->destination->address.inet.sin_addr.s_addr);
ob_append_ui16(buff, subscriber->destination->address.inet.sin_port);
DEBUGF(overlayrouting, "Added STUN info for %s", alloca_tohex_sid_t(subscriber->sid));
}else{
DEBUGF(overlayrouting, "Unable to give address of %s, %d", alloca_tohex_sid_t(subscriber->sid),subscriber->reachable);
}
}
DEFINE_BINDING(MDP_PORT_STUNREQ, overlay_mdp_service_stun_req);
static int overlay_mdp_service_stun_req(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
DEBUGF(overlayrouting, "Processing STUN request from %s", alloca_tohex_sid_t(header->source->sid));
struct internal_mdp_header reply;
bzero(&reply, sizeof reply);
mdp_init_response(header, &reply);
reply.qos = OQ_MESH_MANAGEMENT;
struct overlay_buffer *replypayload = ob_new();
ob_limitsize(replypayload, MDP_MTU);
ob_checkpoint(replypayload);
while (ob_remaining(payload) > 0) {
struct subscriber *subscriber=NULL;
if (overlay_address_parse(NULL, payload, &subscriber))
break;
if (!subscriber){
DEBUGF(overlayrouting, "Unknown subscriber");
continue;
}
overlay_append_unicast_address(subscriber, replypayload);
if (ob_overrun(payload))
break;
ob_checkpoint(replypayload);
}
ob_rewind(replypayload);
if (ob_position(replypayload)){
DEBUGF(overlayrouting, "Sending reply");
ob_flip(replypayload);
overlay_send_frame(&reply, replypayload);
}
ob_free(replypayload);
return 0;
}

View File

@ -624,7 +624,6 @@ enum rhizome_bundle_status rhizome_retrieve_manifest_by_prefix(const unsigned ch
enum rhizome_bundle_status rhizome_retrieve_manifest_by_hash_prefix(const uint8_t *prefix, unsigned prefix_len, rhizome_manifest *m);
enum rhizome_bundle_status rhizome_retrieve_bar_by_hash_prefix(const uint8_t *prefix, unsigned prefix_len, rhizome_bar_t *bar);
int rhizome_advertise_manifest(struct subscriber *dest, rhizome_manifest *m);
int rhizome_mdp_send_block(struct subscriber *dest, const rhizome_bid_t *bid, uint64_t version, uint64_t fileOffset, uint32_t bitmap, uint16_t blockLength);
int rhizome_delete_bundle(const rhizome_bid_t *bidp);
int rhizome_delete_manifest(const rhizome_bid_t *bidp);
int rhizome_delete_payload(const rhizome_bid_t *bidp);
@ -767,7 +766,6 @@ void rhizome_direct_bundle_iterator_unlimit(rhizome_direct_bundle_cursor *r);
int rhizome_direct_bundle_iterator_pickle_range(rhizome_direct_bundle_cursor *r,
unsigned char *pickled,
int pickle_buffer_size);
rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix, size_t prefix_length);
int rhizome_direct_bundle_iterator_unpickle_range(rhizome_direct_bundle_cursor *r,
const unsigned char *pickled,
int pickle_buffer_size);
@ -821,15 +819,14 @@ extern rhizome_direct_sync_request *rd_sync_handles[RHIZOME_DIRECT_MAX_SYNC_HAND
extern int rd_sync_handle_count;
rhizome_direct_sync_request
*rhizome_direct_new_sync_request(
void (*transport_specific_dispatch_function)
(struct rhizome_direct_sync_request *),
size_t buffer_size, int interval, int mode,
*rhizome_direct_new_sync_request(void (*transport_specific_dispatch_function)(struct rhizome_direct_sync_request *),
size_t buffer_size,
int interval,
int mode,
void *transport_specific_state);
int rhizome_direct_continue_sync_request(rhizome_direct_sync_request *r);
int rhizome_direct_conclude_sync_request(rhizome_direct_sync_request *r);
rhizome_direct_bundle_cursor *rhizome_direct_get_fill_response
(unsigned char *buffer,int size,int max_response_bytes);
rhizome_direct_bundle_cursor *rhizome_direct_get_fill_response(unsigned char *buffer,int size,int max_response_bytes);
typedef struct rhizome_direct_transport_state_http {
int port;

View File

@ -25,6 +25,8 @@
#include "rhizome.h"
#include "instance.h"
DEFINE_FEATURE(cli_rhizome);
static void cli_put_manifest(struct cli_context *context, const rhizome_manifest *m)
{
assert(m->filesize != RHIZOME_SIZE_UNSET);

View File

@ -1,6 +1,7 @@
/*
Serval Mesh Software
Copyright (C) 2010-2012 Paul Gardner-Stephen
Serval DNA Rhizome Direct
Copyright (C) 2012-2015 Serval Project Inc.
Copyright (C) 2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -107,12 +108,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
#include "conf.h"
#include "rhizome.h"
#include "str.h"
#include "commandline.h"
#include <assert.h>
#include "serval.h"
#include "rhizome.h"
#include "conf.h"
#include "str.h"
rhizome_direct_sync_request *rd_sync_handles[RHIZOME_DIRECT_MAX_SYNC_HANDLES];
int rd_sync_handle_count=0;
@ -160,20 +160,6 @@ rhizome_direct_sync_request
rd_sync_handles[rd_sync_handle_count++]=r;
return r;
}
/*
Initiate a synchronisation episode.
*/
int rhizome_direct_start_sync_request(rhizome_direct_sync_request *r)
{
assert(r);
assert(r->syncs_started==r->syncs_completed);
r->syncs_started++;
return rhizome_direct_continue_sync_request(r);
}
int rhizome_direct_continue_sync_request(rhizome_direct_sync_request *r)
{
assert(r);
@ -390,156 +376,6 @@ rhizome_direct_bundle_cursor *rhizome_direct_get_fill_response(unsigned char *bu
return c;
}
rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix, size_t prefix_length)
{
/* Give a BID prefix, e.g., from a BAR, find the matching manifest and return it.
Of course, it is possible that more than one manifest matches. This should
occur only very rarely (with the possible exception of intentional attack, and
even then a 64-bit prefix creates a reasonable barrier. If we move to a new
BAR format with 120 or 128 bits of BID prefix, then we should be safe for some
time, thus this function taking the BID prefix as an input in preparation for
that change).
Of course, we need to be able to find the manifest.
Easiest way is to select with a BID range. We could instead have an extra
database column with the prefix.
*/
rhizome_bid_t low = RHIZOME_BID_ZERO;
rhizome_bid_t high = RHIZOME_BID_MAX;
assert(prefix_length <= sizeof(rhizome_bid_t));
bcopy(bid_prefix, low.binary, prefix_length);
bcopy(bid_prefix, high.binary, prefix_length);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare_bind(&retry,
"SELECT manifest, rowid FROM MANIFESTS WHERE id >= ? AND id <= ?",
RHIZOME_BID_T, &low,
RHIZOME_BID_T, &high,
END);
sqlite3_blob *blob=NULL;
if (sqlite_step_retry(&retry, statement) == SQLITE_ROW)
{
int ret;
int64_t rowid = sqlite3_column_int64(statement, 1);
do ret = sqlite3_blob_open(rhizome_db, "main", "manifests", "bar",
rowid, 0 /* read only */, &blob);
while (sqlite_code_busy(ret) && sqlite_retry(&retry, "sqlite3_blob_open"));
if (!sqlite_code_ok(ret)) {
WHYF("sqlite3_blob_open() failed, %s", sqlite3_errmsg(rhizome_db));
sqlite3_finalize(statement);
return NULL;
}
sqlite_retry_done(&retry, "sqlite3_blob_open");
/* Read manifest data from blob */
size_t manifestblobsize = sqlite3_column_bytes(statement, 0);
if (manifestblobsize<1||manifestblobsize>1024) goto error;
const char *manifestblob = (char *) sqlite3_column_blob(statement, 0);
if (!manifestblob)
goto error;
rhizome_manifest *m = rhizome_new_manifest();
if (!m)
goto error;
memcpy(m->manifestdata, manifestblob, manifestblobsize);
m->manifest_all_bytes = manifestblobsize;
if ( rhizome_manifest_parse(m) == -1
|| !rhizome_manifest_validate(m)
) {
rhizome_manifest_free(m);
goto error;
}
DEBUGF(rhizome_direct, "Read manifest");
sqlite3_blob_close(blob);
sqlite3_finalize(statement);
return m;
error:
sqlite3_blob_close(blob);
sqlite3_finalize(statement);
return NULL;
}
else
{
DEBUGF(rhizome_direct, "no matching manifests");
sqlite3_finalize(statement);
return NULL;
}
}
static int rhizome_sync_with_peers(int mode, int peer_count, const struct config_rhizome_peer *const *peers)
{
/* Get iterator capable of 64KB buffering.
In future we should parse the sync URL and base the buffer size on the
transport and allowable traffic volumes. */
rhizome_direct_transport_state_http *state = emalloc_zero(sizeof(rhizome_direct_transport_state_http));
/* XXX This code runs each sync in series, when we can probably do them in
parallel. But we can't really do them in parallel until we make the
synchronisation process fully asynchronous, which probably won't happen
for a while yet.
Also, we don't currently parse the URI protocol field fully. */
int peer_number;
for (peer_number = 0; peer_number < peer_count; ++peer_number) {
const struct config_rhizome_peer *peer = peers[peer_number];
if (strcasecmp(peer->protocol, "http") != 0)
return WHYF("Unsupported Rhizome Direct protocol %s", alloca_str_toprint(peer->protocol));
strbuf h = strbuf_local_buf(state->host);
strbuf_puts(h, peer->host);
if (strbuf_overrun(h))
return WHYF("Rhizome Direct host name too long: %s", alloca_str_toprint(peer->host));
state->port = peer->port;
DEBUGF(rhizome_direct, "Rhizome direct peer is %s://%s:%d", peer->protocol, state->host, state->port);
rhizome_direct_sync_request *s = rhizome_direct_new_sync_request(rhizome_direct_http_dispatch, 65536, 0, mode, state);
rhizome_direct_start_sync_request(s);
if (rd_sync_handle_count > 0)
while (fd_poll() && rd_sync_handle_count > 0)
;
}
return 0;
}
DEFINE_CMD(app_rhizome_direct_sync, 0,
"Synchronise with the specified Rhizome Direct server.",
"rhizome","direct","push|pull|sync","[<url>]");
static int app_rhizome_direct_sync(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
{
DEBUG_cli_parsed(verbose, parsed);
/* Attempt to connect with a remote Rhizome Direct instance,
and negotiate which BARs to synchronise. */
const char *modeName = (parsed->argc >= 3 ? parsed->args[2] : "sync");
int mode=3; /* two-way sync */
if (!strcasecmp(modeName,"push")) mode=1; /* push only */
if (!strcasecmp(modeName,"pull")) mode=2; /* pull only */
DEBUGF(rhizome_direct, "sync direction = %d",mode);
rhizome_opendb();
if (parsed->args[3]) {
struct config_rhizome_peer peer;
const struct config_rhizome_peer *peers[1] = { &peer };
int result = cf_opt_rhizome_peer_from_uri(&peer, parsed->args[3]);
if (result == CFOK)
return rhizome_sync_with_peers(mode, 1, peers);
else {
strbuf b = strbuf_alloca(128);
strbuf_cf_flag_reason(b, result);
return WHYF("Invalid peer URI %s -- %s", alloca_str_toprint(parsed->args[3]), strbuf_str(b));
}
} else if (config.rhizome.direct.peer.ac == 0) {
DEBUG(rhizome_direct, "No rhizome direct peers were configured or supplied");
return -1;
} else {
const struct config_rhizome_peer *peers[config.rhizome.direct.peer.ac];
unsigned i;
for (i = 0; i < config.rhizome.direct.peer.ac; ++i)
peers[i] = &config.rhizome.direct.peer.av[i].value;
return rhizome_sync_with_peers(mode, config.rhizome.direct.peer.ac, peers);
}
}
rhizome_direct_bundle_cursor *rhizome_direct_bundle_iterator(size_t buffer_size)
{
rhizome_direct_bundle_cursor *r=calloc(sizeof(rhizome_direct_bundle_cursor),1);

110
rhizome_direct_cli.c Normal file
View File

@ -0,0 +1,110 @@
/*
Serval DNA Rhizome Direct
Copyright (C) 2012-2015 Serval Project Inc.
Copyright (C) 2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "feature.h"
#include "commandline.h"
#include "rhizome.h"
#include "mem.h"
#include "conf.h"
#include "debug.h"
#include "str.h"
DEFINE_FEATURE(cli_rhizome_direct);
/*
Initiate a synchronisation episode.
*/
static int rhizome_direct_start_sync_request(rhizome_direct_sync_request *r)
{
assert(r);
assert(r->syncs_started==r->syncs_completed);
r->syncs_started++;
return rhizome_direct_continue_sync_request(r);
}
static int rhizome_sync_with_peers(int mode, int peer_count, const struct config_rhizome_peer *const *peers)
{
/* Get iterator capable of 64KB buffering.
In future we should parse the sync URL and base the buffer size on the
transport and allowable traffic volumes. */
rhizome_direct_transport_state_http *state = emalloc_zero(sizeof(rhizome_direct_transport_state_http));
/* XXX This code runs each sync in series, when we can probably do them in
parallel. But we can't really do them in parallel until we make the
synchronisation process fully asynchronous, which probably won't happen
for a while yet.
Also, we don't currently parse the URI protocol field fully. */
int peer_number;
for (peer_number = 0; peer_number < peer_count; ++peer_number) {
const struct config_rhizome_peer *peer = peers[peer_number];
if (strcasecmp(peer->protocol, "http") != 0)
return WHYF("Unsupported Rhizome Direct protocol %s", alloca_str_toprint(peer->protocol));
strbuf h = strbuf_local_buf(state->host);
strbuf_puts(h, peer->host);
if (strbuf_overrun(h))
return WHYF("Rhizome Direct host name too long: %s", alloca_str_toprint(peer->host));
state->port = peer->port;
DEBUGF(rhizome_direct, "Rhizome direct peer is %s://%s:%d", peer->protocol, state->host, state->port);
rhizome_direct_sync_request *s = rhizome_direct_new_sync_request(rhizome_direct_http_dispatch, 65536, 0, mode, state);
rhizome_direct_start_sync_request(s);
if (rd_sync_handle_count > 0)
while (fd_poll() && rd_sync_handle_count > 0)
;
}
return 0;
}
DEFINE_CMD(app_rhizome_direct_sync, 0,
"Synchronise with the specified Rhizome Direct server.",
"rhizome","direct","push|pull|sync","[<url>]");
static int app_rhizome_direct_sync(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
{
DEBUG_cli_parsed(verbose, parsed);
/* Attempt to connect with a remote Rhizome Direct instance,
and negotiate which BARs to synchronise. */
const char *modeName = (parsed->argc >= 3 ? parsed->args[2] : "sync");
int mode=3; /* two-way sync */
if (!strcasecmp(modeName,"push")) mode=1; /* push only */
if (!strcasecmp(modeName,"pull")) mode=2; /* pull only */
DEBUGF(rhizome_direct, "sync direction = %d",mode);
rhizome_opendb();
if (parsed->args[3]) {
struct config_rhizome_peer peer;
const struct config_rhizome_peer *peers[1] = { &peer };
int result = cf_opt_rhizome_peer_from_uri(&peer, parsed->args[3]);
if (result == CFOK)
return rhizome_sync_with_peers(mode, 1, peers);
else {
strbuf b = strbuf_alloca(128);
strbuf_cf_flag_reason(b, result);
return WHYF("Invalid peer URI %s -- %s", alloca_str_toprint(parsed->args[3]), strbuf_str(b));
}
} else if (config.rhizome.direct.peer.ac == 0) {
DEBUG(rhizome_direct, "No rhizome direct peers were configured or supplied");
return -1;
} else {
const struct config_rhizome_peer *peers[config.rhizome.direct.peer.ac];
unsigned i;
for (i = 0; i < config.rhizome.direct.peer.ac; ++i)
peers[i] = &config.rhizome.direct.peer.av[i].value;
return rhizome_sync_with_peers(mode, config.rhizome.direct.peer.ac, peers);
}
}

View File

@ -31,6 +31,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "strbuf_helpers.h"
#include "socket.h"
DEFINE_FEATURE(http_rhizome_direct);
DECLARE_HANDLER("/rhizome/import", rhizome_direct_import);
DECLARE_HANDLER("/rhizome/enquiry", rhizome_direct_enquiry);
DECLARE_HANDLER("/rhizome/", rhizome_direct_dispatch);
@ -461,6 +463,8 @@ static int fill_buffer(int sock, unsigned char *buffer, int len, int buffer_size
return 0;
}
static rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix, size_t prefix_length);
void rhizome_direct_http_dispatch(rhizome_direct_sync_request *r)
{
DEBUGF(rhizome_tx, "Dispatch size_high=%"PRId64,r->cursor->size_high);
@ -806,3 +810,85 @@ void rhizome_direct_http_dispatch(rhizome_direct_sync_request *r)
But this will do for now. */
rhizome_direct_continue_sync_request(r);
}
static rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix, size_t prefix_length)
{
/* Give a BID prefix, e.g., from a BAR, find the matching manifest and return it.
Of course, it is possible that more than one manifest matches. This should
occur only very rarely (with the possible exception of intentional attack, and
even then a 64-bit prefix creates a reasonable barrier. If we move to a new
BAR format with 120 or 128 bits of BID prefix, then we should be safe for some
time, thus this function taking the BID prefix as an input in preparation for
that change).
Of course, we need to be able to find the manifest.
Easiest way is to select with a BID range. We could instead have an extra
database column with the prefix.
*/
rhizome_bid_t low = RHIZOME_BID_ZERO;
rhizome_bid_t high = RHIZOME_BID_MAX;
assert(prefix_length <= sizeof(rhizome_bid_t));
bcopy(bid_prefix, low.binary, prefix_length);
bcopy(bid_prefix, high.binary, prefix_length);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare_bind(&retry,
"SELECT manifest, rowid FROM MANIFESTS WHERE id >= ? AND id <= ?",
RHIZOME_BID_T, &low,
RHIZOME_BID_T, &high,
END);
sqlite3_blob *blob=NULL;
if (sqlite_step_retry(&retry, statement) == SQLITE_ROW)
{
int ret;
int64_t rowid = sqlite3_column_int64(statement, 1);
do ret = sqlite3_blob_open(rhizome_db, "main", "manifests", "bar",
rowid, 0 /* read only */, &blob);
while (sqlite_code_busy(ret) && sqlite_retry(&retry, "sqlite3_blob_open"));
if (!sqlite_code_ok(ret)) {
WHYF("sqlite3_blob_open() failed, %s", sqlite3_errmsg(rhizome_db));
sqlite3_finalize(statement);
return NULL;
}
sqlite_retry_done(&retry, "sqlite3_blob_open");
/* Read manifest data from blob */
size_t manifestblobsize = sqlite3_column_bytes(statement, 0);
if (manifestblobsize<1||manifestblobsize>1024) goto error;
const char *manifestblob = (char *) sqlite3_column_blob(statement, 0);
if (!manifestblob)
goto error;
rhizome_manifest *m = rhizome_new_manifest();
if (!m)
goto error;
memcpy(m->manifestdata, manifestblob, manifestblobsize);
m->manifest_all_bytes = manifestblobsize;
if ( rhizome_manifest_parse(m) == -1
|| !rhizome_manifest_validate(m)
) {
rhizome_manifest_free(m);
goto error;
}
DEBUGF(rhizome_direct, "Read manifest");
sqlite3_blob_close(blob);
sqlite3_finalize(statement);
return m;
error:
sqlite3_blob_close(blob);
sqlite3_finalize(statement);
return NULL;
}
else
{
DEBUGF(rhizome_direct, "no matching manifests");
sqlite3_finalize(statement);
return NULL;
}
}

View File

@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "str.h"
#include "strbuf.h"
DEFINE_FEATURE(http_rhizome);
DECLARE_HANDLER("/rhizome/status", rhizome_status_page);
DECLARE_HANDLER("/rhizome/file/", rhizome_file_page);
DECLARE_HANDLER("/rhizome/manifestbyprefix/", manifest_by_prefix_page);

View File

@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "base64.h"
#include "strbuf_helpers.h"
DEFINE_FEATURE(http_rest_rhizome);
DECLARE_HANDLER("/restful/rhizome/bundlelist.json", restful_rhizome_bundlelist_json);
DECLARE_HANDLER("/restful/rhizome/newsince/", restful_rhizome_newsince);
DECLARE_HANDLER("/restful/rhizome/insert", restful_rhizome_insert);

View File

@ -1,5 +1,5 @@
/*
Serval DNA header file
Serval DNA link-state routing
Copyright (C) 2015 Serval Project Inc.
This program is free software; you can redistribute it and/or
@ -46,4 +46,4 @@ int link_state_legacy_ack(struct overlay_frame *frame, time_ms_t now);
DECLARE_TRIGGER(nbr_change, struct subscriber *neighbour, uint8_t found, unsigned count);
DECLARE_TRIGGER(link_change, struct subscriber *subscriber, int prior_reachable);
#endif
#endif // __SERVAL_DNA__ROUTE_LINK_H

View File

@ -1,6 +1,6 @@
/*
/*
Serval DNA header file
Copyright (C) 2010-2012 Paul Gardner-Stephen
Copyright (C) 2010-2012 Paul Gardner-Stephen
Copyright (C) 2012-2013 Serval Project Inc.
This program is free software; you can redistribute it and/or
@ -149,9 +149,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
/* Limit packet payloads to minimise packet loss of big packets in mesh networks */
#define MAX_DATA_BYTES 256
extern const char version_servald[];
extern const char copyright_servald[];
int rhizome_enabled();
int rhizome_http_server_running();

75
servald_features.c Normal file
View File

@ -0,0 +1,75 @@
/*
Serval DNA daemon features
Copyright (C) 2016 Flinders University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "feature.h"
void servald_features()
{
USE_FEATURE(cli_version);
USE_FEATURE(cli_echo);
USE_FEATURE(cli_log);
USE_FEATURE(cli_config);
USE_FEATURE(cli_server);
USE_FEATURE(cli_keyring);
USE_FEATURE(cli_network);
USE_FEATURE(cli_rhizome);
USE_FEATURE(cli_meshms);
USE_FEATURE(cli_monitor);
USE_FEATURE(cli_msp_proxy);
USE_FEATURE(cli_vomp_console);
USE_FEATURE(cli_rhizome_direct);
USE_FEATURE(mdp_binding_MDP_PORT_ECHO);
USE_FEATURE(mdp_binding_MDP_PORT_TRACE);
USE_FEATURE(mdp_binding_MDP_PORT_KEYMAPREQUEST);
USE_FEATURE(mdp_binding_MDP_PORT_DNALOOKUP);
USE_FEATURE(mdp_binding_MDP_PORT_PROBE);
USE_FEATURE(mdp_binding_MDP_PORT_STUN);
USE_FEATURE(mdp_binding_MDP_PORT_STUNREQ);
USE_FEATURE(mdp_binding_MDP_PORT_LINKSTATE);
USE_FEATURE(mdp_binding_MDP_PORT_VOMP);
USE_FEATURE(mdp_binding_MDP_PORT_RHIZOME_SYNC);
USE_FEATURE(mdp_binding_MDP_PORT_RHIZOME_SYNC_KEYS);
USE_FEATURE(mdp_binding_MDP_PORT_RHIZOME_REQUEST);
USE_FEATURE(mdp_binding_MDP_PORT_RHIZOME_RESPONSE);
USE_FEATURE(mdp_binding_MDP_PORT_RHIZOME_MANIFEST_REQUEST);
USE_FEATURE(http_server);
USE_FEATURE(http_rhizome);
USE_FEATURE(http_rhizome_direct);
USE_FEATURE(http_rest_keyring);
USE_FEATURE(http_rest_rhizome);
USE_FEATURE(http_rest_meshms);
}
#include <assert.h>
#include "overlay_address.h"
#include "rhizome.h"
#include "cli.h"
#include "keyring.h"
__thread keyring_file *keyring = NULL;
void cli_cleanup()
{
/* clean up after ourselves */
rhizome_close_db();
free_subscribers();
assert(keyring==NULL);
}

View File

@ -43,10 +43,8 @@ int servald_main(int argc, char **argv)
sigaction(SIGABRT, &sig, NULL);
/* Setup i/o signal handlers */
signal(SIGPIPE,sigPipeHandler);
signal(SIGIO,sigIoHandler);
cf_init();
signal(SIGPIPE, sigPipeHandler);
signal(SIGIO, sigIoHandler);
int status = commandline_main_stdio(stdout, argv[0], argc - 1, (const char*const*)&argv[1]);
@ -58,16 +56,22 @@ int servald_main(int argc, char **argv)
char crash_handler_clue[1024] = "no clue";
static void crash_handler(int signal)
static void crash_handler(int signum)
{
LOGF(LOG_LEVEL_FATAL, "Caught signal %s", alloca_signal_name(signal));
LOGF(LOG_LEVEL_FATAL, "Caught signal %s", alloca_signal_name(signum));
LOGF(LOG_LEVEL_FATAL, "The following clue may help: %s", crash_handler_clue);
dump_stack(LOG_LEVEL_FATAL);
BACKTRACE;
// Now die of the same signal, so that our exit status reflects the cause.
INFOF("Re-sending signal %d to self", signal);
kill(getpid(), signal);
// If that didn't work, then die normally.
INFOF("exit(%d)", -signal);
exit(-signal);
// Exit with a status code indicating the caught signal. This involves removing the signal
// handler for the caught signal then re-sending the same signal to ourself. If that doesn't
// work, then exit with an error code.
struct sigaction sig;
bzero(&sig, sizeof sig);
sig.sa_flags = 0;
sig.sa_handler = SIG_DFL;
sigemptyset(&sig.sa_mask);
sigaction(signum, &sig, NULL);
INFOF("Re-sending signal %d to self", signum);
kill(getpid(), signum); // should terminate self
exit(-1);
}

View File

@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "server.h"
#include "serval.h"
#include "rhizome.h"
#include "conf.h"
#include "log.h"
#include "str.h"
@ -48,19 +49,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "mdp_client.h"
#include "route_link.h"
DEFINE_FEATURE(cli_server);
#define PROC_SUBDIR "proc"
#define PIDFILE_NAME "servald.pid"
#define STOPFILE_NAME "servald.stop"
__thread enum server_mode serverMode = SERVER_NOT_RUNNING;
__thread keyring_file *keyring=NULL;
struct pid_tid {
pid_t pid;
pid_t tid;
};
static char pidfile_path[256];
static struct pid_tid server_pid_tid = { .pid = 0, .tid = 0 };
static int server_pidfd = -1;
static int server();
@ -73,14 +74,6 @@ static const char *_server_pidfile_path(struct __sourceloc __whence);
static int server_write_proc_state(const char *path, const char *fmt, ...);
static int server_get_proc_state(const char *path, char *buff, size_t buff_len);
void cli_cleanup()
{
/* clean up after ourselves */
rhizome_close_db();
free_subscribers();
assert(keyring==NULL);
}
static pid_t gettid()
{
#ifdef HAVE_LINUX_THREADS
@ -182,6 +175,7 @@ static int send_signal(const struct pid_tid *id, int signum)
static const char *_server_pidfile_path(struct __sourceloc __whence)
{
static char pidfile_path[256];
if (!pidfile_path[0]) {
if (!FORMF_SERVAL_RUN_PATH(pidfile_path, PIDFILE_NAME))
return NULL;
@ -689,13 +683,11 @@ static int app_server_start(const struct cli_parsed *parsed, struct cli_context
RETURN(-1);
int seed = cli_arg(parsed, "--seed", NULL, NULL, NULL) == 0;
int foregroundP = cli_arg(parsed, "foreground", NULL, NULL, NULL) == 0;
if (config.interfaces.ac == 0)
NOWHENCE(WARN("No network interfaces configured (empty 'interfaces' config option)"));
/* Create the instance directory if it does not yet exist */
if (create_serval_instance_dir() == -1)
RETURN(-1);
/* Now that we know our instance path, we can ask for the default set of
network interfaces that we will take interest in. */
if (config.interfaces.ac == 0)
NOWHENCE(WARN("No network interfaces configured (empty 'interfaces' config option)"));
struct pid_tid id = get_server_pid_tid();
if (id.pid < 0)
RETURN(-1);

View File

@ -26,12 +26,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "os.h"
#include "route_link.h"
DEFINE_FEATURE(http_server);
DECLARE_HANDLER("/", root_page);
DECLARE_HANDLER("/static/", static_page);
DECLARE_HANDLER("/interface/", interface_page);
DECLARE_HANDLER("/neighbour/", neighbour_page);
DECLARE_HANDLER("/favicon.ico", fav_icon_header);
DECLARE_HANDLER("/", root_page);
static int root_page(httpd_request *r, const char *remainder)
{

View File

@ -2,17 +2,17 @@
Serval DNA signal handlers
Copyright (C) 2014 Serval Project Inc.
Copyright (C) 2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

View File

@ -1,6 +1,7 @@
# The "client" source files do not depend on "serval.h" or "rhizome.h", ie,
# they can be linked into executables other than servald.
SERVAL_CLIENT_SOURCES = \
base64.c \
cli.c \
cli_stdio.c \
commandline.c \
@ -9,14 +10,20 @@ SERVAL_CLIENT_SOURCES = \
conf_parse.c \
conf_schema.c \
console.c \
context1.c \
dataformats.c \
echo_cli.c \
fdqueue.c \
instance.c \
limit.c \
logMessage.c \
log_cli.c \
log_context.c \
log_stderr.c \
log_util.c \
mem.c \
net.c \
numeric_str.c \
os.c \
performance_timing.c \
rotbuf.c \
@ -25,21 +32,14 @@ SERVAL_CLIENT_SOURCES = \
strbuf.c \
strbuf_helpers.c \
str.c \
numeric_str.c \
base64.c \
uri.c \
strlcpy.c \
test_cli.c \
uri.c \
uuid.c \
version_cli.c \
whence.c \
xprintf.c
# These objects do not belong in the Serval DNA daemon but are available for
# client applications.
SERVAL_LIB_SOURCES = \
log_context.c \
log_on_config_change.c \
log_stderr.c
# These source files are imported and do not depend on any local header files.
# They also take a long time to compile, so their dependencies should be as
# narrow as possible to avoid unnecessary recompilations when developers modify
@ -51,9 +51,6 @@ SERVAL_DAEMON_SOURCES = \
main.c \
servald_main.c \
conf_cli.c \
rhizome_cli.c \
keyring_cli.c \
network_cli.c \
crypto.c \
directory_client.c \
dna_helper.c \
@ -61,14 +58,15 @@ SERVAL_DAEMON_SOURCES = \
httpd.c \
http_server.c \
keyring.c \
keyring_cli.c \
keyring_restful.c \
log.c \
lsif.c \
radio_link.c \
meshms.c \
meshmb.c \
meshms_cli.c \
message_ply.c \
keyring_restful.c \
meshms_cli.c \
meshms_restful.c \
msp_client.c \
msp_proxy.c \
@ -79,13 +77,20 @@ SERVAL_DAEMON_SOURCES = \
overlay_buffer.c \
overlay_interface.c \
overlay_link.c \
overlay_probe.c \
overlay_stun.c \
overlay_stunreq.c \
overlay_packetradio.c \
overlay_queue.c \
overlay_mdp.c \
overlay_mdp_services.c \
overlay_mdp_echo.c \
overlay_mdp_trace.c \
overlay_mdp_keymaprequest.c \
overlay_mdp_dnalookup.c \
mdp_filter.c \
msp_server.c \
nibble_tree.c \
network_cli.c \
overlay_olsr.c \
overlay_packetformats.c \
overlay_payload.c \
@ -94,15 +99,18 @@ SERVAL_DAEMON_SOURCES = \
rhizome_bundle.c \
rhizome_crypto.c \
rhizome_database.c \
overlay_mdp_rhizome.c \
rhizome_direct.c \
rhizome_direct_cli.c \
rhizome_direct_http.c \
rhizome_fetch.c \
rhizome_http.c \
rhizome_restful.c \
rhizome_packetformats.c \
rhizome_store.c \
rhizome_sync.c \
rhizome_sync_keys.c \
rhizome_restful.c \
rhizome_cli.c \
sync_keys.c \
serval_packetvisualise.c \
server.c \
@ -119,14 +127,6 @@ SERVAL_DAEMON_JNI_SOURCES = \
jni_commandline.c \
jni_server.c
TEST_SOURCES = \
main.c \
servald_main.c \
test_cli.c \
log_context.c \
log_stderr.c \
context1.c
MDP_CLIENT_SOURCES = \
mdp_client.c

View File

@ -34,8 +34,7 @@
#include "mem.h"
#include "str.h"
void cli_cleanup(){}
void cf_on_config_change(){}
DEFINE_FEATURE(cli_tests);
DEFINE_CMD(app_byteorder_test, 0,
"Run byte order handling test",
@ -323,4 +322,3 @@ static int app_config_test(const struct cli_parsed *UNUSED(parsed), struct cli_c
}
return 0;
}

30
test_features.c Normal file
View File

@ -0,0 +1,30 @@
/*
Serval DNA test features
Copyright (C) 2016 Flinders University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "feature.h"
void test_features()
{
USE_FEATURE(cli_version);
USE_FEATURE(cli_echo);
USE_FEATURE(cli_log);
USE_FEATURE(cli_tests);
}
void cli_cleanup() {}

View File

@ -18,10 +18,10 @@
source "${0%/*}/../testconfig.sh"
# Utility function for setting up servald JNI fixtures:
# - check that libserval.so is present
# - set LD_LIBRARY_PATH so that libserval.so can be found
# - check that libservald.so is present
# - set LD_LIBRARY_PATH so that libservald.so can be found
setup_servald_so() {
assert [ -r "$servald_build_root/libserval.so" ]
assert [ -r "$servald_build_root/libservald.so" ]
export LD_LIBRARY_PATH="$servald_build_root"
}

39
version_cli.c Normal file
View File

@ -0,0 +1,39 @@
/*
Serval DNA version and copyright
Copyright (C) 2014-2015 Serval Project Inc.
Copyright (C) 2016 Flinders University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "feature.h"
#include "commandline.h"
#include "version_servald.h"
DEFINE_FEATURE(cli_version);
DEFINE_CMD(version_message, CLIFLAG_PERMISSIVE_CONFIG,
"Display version and copyright information.",
"version|copyright");
static int version_message(const struct cli_parsed *UNUSED(parsed), struct cli_context *UNUSED(context))
{
printf("Serval DNA version %s\n%s\n", version_servald, copyright_servald);
printf("\
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n\
This is free software: you are free to change and redistribute it.\n\
There is NO WARRANTY, to the extent permitted by law.\n\
");
return 0;
}

View File

@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "version_servald.h"
#ifndef SERVALD_VERSION
#error "SERVALD_VERSION is not defined"
#endif

21
version_servald.h Normal file
View File

@ -0,0 +1,21 @@
/*
Serval DNA version and copyright strings
Copyright (C) 2016 Flinders University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
extern const char version_servald[];
extern const char copyright_servald[];

View File

@ -382,6 +382,8 @@ static void monitor_read(struct sched_ent *alarm){
}
}
DEFINE_FEATURE(cli_vomp_console);
DEFINE_CMD(app_vomp_console, 0,
"Test phone call life-cycle from the console",
"console");