summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2014-04-26 00:46:33 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2014-04-26 22:46:05 +0200
commit36690c7203f0e46665f328fbe82ae3bd573cc6ff (patch)
tree761707cbd83e499913277fc931e32d05bf3c32cc
parent64ce1c0f51b4d0c07c124071ea2cd8002eccd45d (diff)
downloadfastd-36690c7203f0e46665f328fbe82ae3bd573cc6ff.tar
fastd-36690c7203f0e46665f328fbe82ae3bd573cc6ff.zip
Implement async verify
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/async.c24
-rw-r--r--src/async.h24
-rw-r--r--src/config.c3
-rw-r--r--src/fastd.h6
-rw-r--r--src/peer.c42
-rw-r--r--src/peer.h16
-rw-r--r--src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c1
-rw-r--r--src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h3
-rw-r--r--src/protocols/ec25519_fhmqvc/handshake.c70
-rw-r--r--src/types.h6
-rw-r--r--src/verify.c111
-rw-r--r--src/verify.h33
13 files changed, 279 insertions, 61 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f9143db..9802883 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -39,6 +39,7 @@ add_executable(fastd
socket.c
tuntap.c
vector.c
+ verify.c
${BISON_fastd_config_parse_OUTPUTS}
)
set_property(TARGET fastd PROPERTY COMPILE_FLAGS "${FASTD_CFLAGS}")
diff --git a/src/async.c b/src/async.c
index cb9ee14..982543d 100644
--- a/src/async.c
+++ b/src/async.c
@@ -41,9 +41,7 @@ void fastd_async_init(void) {
fastd_setfl(ctx.async_wfd, O_NONBLOCK, 0);
}
-static void handle_resolve_return(const void *buf) {
- const fastd_async_resolve_return_t *resolve_return = buf;
-
+static void handle_resolve_return(const fastd_async_resolve_return_t *resolve_return) {
fastd_peer_t *peer = fastd_peer_find_by_id(resolve_return->peer_id);
if (!peer)
return;
@@ -55,6 +53,20 @@ static void handle_resolve_return(const void *buf) {
fastd_peer_handle_resolve(peer, remote, resolve_return->n_addr, resolve_return->addr);
}
+static void handle_verify_return(const fastd_async_verify_return_t *verify_return) {
+ fastd_peer_t *peer = fastd_peer_find_by_id(verify_return->peer_id);
+ if (!peer)
+ return;
+
+ if (peer->config)
+ exit_bug("verify return for permanent peer");
+
+ fastd_peer_set_verified(peer, verify_return->ok);
+
+ conf.protocol->handle_verify_return(peer, verify_return->sock, &verify_return->local_addr, &verify_return->remote_addr,
+ verify_return->method, verify_return->protocol_data, verify_return->ok);
+}
+
void fastd_async_handle(void) {
fastd_async_hdr_t header;
struct iovec vec[2] = {
@@ -82,7 +94,11 @@ void fastd_async_handle(void) {
switch (header.type) {
case ASYNC_TYPE_RESOLVE_RETURN:
- handle_resolve_return(buf);
+ handle_resolve_return((const fastd_async_resolve_return_t *)buf);
+ break;
+
+ case ASYNC_TYPE_VERIFY_RETURN:
+ handle_verify_return((const fastd_async_verify_return_t *)buf);
break;
default:
diff --git a/src/async.h b/src/async.h
index f2a8f20..fd6ebd5 100644
--- a/src/async.h
+++ b/src/async.h
@@ -30,13 +30,33 @@
#include "peer.h"
-struct fastd_async_resolve_return {
+typedef enum fastd_async_type {
+ ASYNC_TYPE_RESOLVE_RETURN,
+ ASYNC_TYPE_VERIFY_RETURN,
+} fastd_async_type_t;
+
+
+typedef struct fastd_async_resolve_return {
uint64_t peer_id;
size_t remote;
size_t n_addr;
fastd_peer_address_t addr[];
-};
+} fastd_async_resolve_return_t;
+
+typedef struct fastd_async_verify_return {
+ bool ok;
+
+ uint64_t peer_id;
+
+ const fastd_method_info_t *method;
+ fastd_socket_t *sock;
+
+ fastd_peer_address_t local_addr;
+ fastd_peer_address_t remote_addr;
+
+ uint8_t protocol_data[] __attribute__((aligned(8)));
+} fastd_async_verify_return_t;
void fastd_async_init(void);
diff --git a/src/config.c b/src/config.c
index e20bc57..7d826d4 100644
--- a/src/config.c
+++ b/src/config.c
@@ -76,6 +76,9 @@ static void default_config(void) {
conf.key_refresh = 3300; /* 55 minutes */
conf.key_refresh_splay = 300; /* 5 minutes */
+ conf.min_verify_interval = 10;
+ conf.verify_valid_time = 60; /* 1 minute */
+
conf.peer_group = calloc(1, sizeof(fastd_peer_group_config_t));
conf.peer_group->name = strdup("default");
conf.peer_group->max_connections = -1;
diff --git a/src/fastd.h b/src/fastd.h
index 838ce94..2f9f12a 100644
--- a/src/fastd.h
+++ b/src/fastd.h
@@ -58,8 +58,9 @@ struct fastd_protocol {
bool (*peer_check)(fastd_peer_config_t *peer_conf);
bool (*peer_check_temporary)(fastd_peer_t *peer);
- void (*handshake_init)(const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer);
+ void (*handshake_init)(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer);
void (*handshake_handle)(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const fastd_handshake_t *handshake, const fastd_method_info_t *method);
+ void (*handle_verify_return)(fastd_peer_t *peer, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, const fastd_method_info_t *method, const void *protocol_data, bool ok);
void (*handle_recv)(fastd_peer_t *peer, fastd_buffer_t buffer);
void (*send)(fastd_peer_t *peer, fastd_buffer_t buffer);
@@ -153,6 +154,9 @@ struct fastd_config {
unsigned min_handshake_interval;
unsigned min_resolve_interval;
+ unsigned min_verify_interval;
+ unsigned verify_valid_time;
+
char *ifname;
size_t n_bind_addrs;
diff --git a/src/peer.c b/src/peer.c
index 860cf1d..eef7d0f 100644
--- a/src/peer.c
+++ b/src/peer.c
@@ -688,7 +688,8 @@ fastd_peer_t* fastd_peer_add(fastd_peer_config_t *peer_conf) {
peer->group = ctx.peer_group;
- fastd_peer_seen(peer);
+ peer->verify_timeout = ctx.now;
+ peer->verify_valid_timeout = ctx.now;
pr_debug("adding temporary peer");
}
@@ -701,35 +702,6 @@ fastd_peer_t* fastd_peer_add(fastd_peer_config_t *peer_conf) {
return peer;
}
-bool fastd_peer_verify_temporary(fastd_peer_t *peer, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *peer_addr) {
- if (!fastd_shell_command_isset(&conf.on_verify))
- exit_bug("tried to verify temporary peer without on-verify command");
-
- /* TODO: async not supported yet */
-
- fastd_shell_env_t *env = fastd_shell_env_alloc();
- fastd_peer_set_shell_env(env, peer, local_addr, peer_addr);
-
- int ret;
- bool ok = fastd_shell_command_exec_sync(&conf.on_verify, env, &ret);
-
- fastd_shell_env_free(env);
-
- if (!ok)
- return false;
-
- if (WIFSIGNALED(ret)) {
- pr_error("verify command exited with signal %i", WTERMSIG(ret));
- return false;
- }
- else if (WEXITSTATUS(ret)) {
- pr_debug("verify command exited with status %i", WEXITSTATUS(ret));
- return false;
- }
-
- return true;
-}
-
static inline void no_valid_address_debug(const fastd_peer_t *peer) {
pr_debug("not sending a handshake to %P (no valid address resolved)", peer);
}
@@ -895,14 +867,16 @@ static bool maintain_peer(fastd_peer_t *peer) {
if (fastd_peer_is_temporary(peer) || fastd_peer_is_established(peer)) {
/* check for peer timeout */
if (fastd_timed_out(&peer->timeout)) {
- if (fastd_peer_is_temporary(peer)) {
+ if (fastd_peer_is_temporary(peer) &&
+ fastd_timed_out(&peer->verify_timeout) &&
+ fastd_timed_out(&peer->verify_valid_timeout)) {
fastd_peer_delete(peer);
return false;
}
- else {
+
+ if (fastd_peer_is_established(peer))
fastd_peer_reset(peer);
- return true;
- }
+ return true;
}
/* check for keepalive timeout */
diff --git a/src/peer.h b/src/peer.h
index c7cf603..8cd23c0 100644
--- a/src/peer.h
+++ b/src/peer.h
@@ -57,6 +57,9 @@ struct fastd_peer {
struct timespec establish_handshake_timeout;
+ struct timespec verify_timeout;
+ struct timespec verify_valid_timeout;
+
fastd_protocol_peer_config_t *protocol_config;
fastd_protocol_peer_state_t *protocol_state;
};
@@ -127,8 +130,6 @@ bool fastd_peer_config_equal(const fastd_peer_config_t *peer1, const fastd_peer_
void fastd_peer_reset(fastd_peer_t *peer);
void fastd_peer_delete(fastd_peer_t *peer);
fastd_peer_t* fastd_peer_add(fastd_peer_config_t *peer_conf);
-bool fastd_peer_verify_temporary(fastd_peer_t *peer, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *peer_addr);
-void fastd_peer_enable_temporary(fastd_peer_t *peer);
void fastd_peer_set_established(fastd_peer_t *peer);
bool fastd_peer_may_connect(fastd_peer_t *peer);
void fastd_peer_handle_resolve(fastd_peer_t *peer, fastd_remote_t *remote, size_t n_addresses, const fastd_peer_address_t *addresses);
@@ -150,6 +151,17 @@ static inline void fastd_peer_unschedule_handshake(fastd_peer_t *peer) {
fastd_dlist_remove(&peer->handshake_entry);
}
+static inline void fastd_peer_set_verifying(fastd_peer_t *peer) {
+ peer->verify_timeout = fastd_in_seconds(conf.min_verify_interval);
+}
+
+static inline void fastd_peer_set_verified(fastd_peer_t *peer, bool ok) {
+ if (ok)
+ peer->verify_valid_timeout = fastd_in_seconds(conf.verify_valid_time);
+ else
+ peer->verify_valid_timeout = ctx.now;
+}
+
static inline bool fastd_peer_handshake_scheduled(fastd_peer_t *peer) {
return fastd_dlist_linked(&peer->handshake_entry);
}
diff --git a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c
index ec19da3..777e731 100644
--- a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c
+++ b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c
@@ -205,6 +205,7 @@ const fastd_protocol_t fastd_protocol_ec25519_fhmqvc = {
.handshake_init = fastd_protocol_ec25519_fhmqvc_handshake_init,
.handshake_handle = fastd_protocol_ec25519_fhmqvc_handshake_handle,
+ .handle_verify_return = fastd_protocol_ec25519_fhmqvc_handle_verify_return,
.handle_recv = protocol_handle_recv,
.send = protocol_send,
diff --git a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h
index fcf9b56..c301822 100644
--- a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h
+++ b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h
@@ -88,8 +88,9 @@ void fastd_protocol_ec25519_fhmqvc_init_peer_state(fastd_peer_t *peer);
void fastd_protocol_ec25519_fhmqvc_reset_peer_state(fastd_peer_t *peer);
void fastd_protocol_ec25519_fhmqvc_free_peer_state(fastd_peer_t *peer);
-void fastd_protocol_ec25519_fhmqvc_handshake_init(const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer);
+void fastd_protocol_ec25519_fhmqvc_handshake_init(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer);
void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const fastd_handshake_t *handshake, const fastd_method_info_t *method);
+void fastd_protocol_ec25519_fhmqvc_handle_verify_return(fastd_peer_t *peer, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, const fastd_method_info_t *method, const void *protocol_data, bool ok);
void fastd_protocol_ec25519_fhmqvc_send_empty(fastd_peer_t *peer, protocol_session_t *session);
diff --git a/src/protocols/ec25519_fhmqvc/handshake.c b/src/protocols/ec25519_fhmqvc/handshake.c
index c4177b4..237732d 100644
--- a/src/protocols/ec25519_fhmqvc/handshake.c
+++ b/src/protocols/ec25519_fhmqvc/handshake.c
@@ -27,6 +27,7 @@
#include "handshake.h"
#include "../../handshake.h"
#include "../../hkdf_sha256.h"
+#include "../../verify.h"
#define HASHBYTES FASTD_SHA256_HASH_BYTES
@@ -268,9 +269,11 @@ static void clear_shared_handshake_key(const fastd_peer_t *peer) {
}
static void respond_handshake(const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer,
- const handshake_key_t *handshake_key, const aligned_int256_t *peer_handshake_key, const fastd_method_info_t *method) {
+ const aligned_int256_t *peer_handshake_key, const fastd_method_info_t *method) {
pr_debug("responding handshake with %P[%I]...", peer, remote_addr);
+ const handshake_key_t *handshake_key = &ctx.protocol_state->handshake_key;
+
if (!update_shared_handshake_key(peer, handshake_key, peer_handshake_key))
return;
@@ -486,12 +489,18 @@ static inline bool allow_unknown(void) {
return fastd_shell_command_isset(&conf.on_verify);
}
-static inline fastd_peer_t* add_temporary(const fastd_peer_address_t *addr, const unsigned char key[PUBLICKEYBYTES]) {
+static fastd_peer_t * add_temporary(fastd_socket_t *sock, const fastd_peer_address_t *addr, const unsigned char key[PUBLICKEYBYTES]) {
if (!allow_unknown()) {
pr_debug("ignoring handshake from %I (unknown key)", addr);
return NULL;
}
+ if (sock->peer) {
+ /* WTF? */
+ pr_debug("ignoring handshake from %I (received on another peer's socket)", addr);
+ return NULL;
+ }
+
if (key_count(key)) {
pr_debug("ignoring handshake from %I (disabled key)", addr);
return NULL;
@@ -509,7 +518,7 @@ static inline fastd_peer_t* add_temporary(const fastd_peer_address_t *addr, cons
}
-void fastd_protocol_ec25519_fhmqvc_handshake_init(const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer) {
+void fastd_protocol_ec25519_fhmqvc_handshake_init(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer) {
fastd_protocol_ec25519_fhmqvc_maintenance();
fastd_buffer_t buffer = fastd_handshake_new_init(3*(4+PUBLICKEYBYTES) /* sender key, receipient key, handshake key */);
@@ -529,6 +538,34 @@ void fastd_protocol_ec25519_fhmqvc_handshake_init(const fastd_socket_t *sock, co
fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer);
}
+typedef struct verify_data {
+ aligned_int256_t peer_handshake_key;
+} verify_data_t;
+
+static bool handle_temporary(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr,
+ fastd_peer_t *peer, const fastd_handshake_t *handshake, const fastd_method_info_t *method) {
+ if (handshake->type != 1 || !fastd_timed_out(&peer->verify_timeout))
+ return !fastd_timed_out(&peer->verify_valid_timeout);
+
+ verify_data_t verify_data;
+ memset(&verify_data, 0, sizeof(verify_data));
+ memcpy(&verify_data.peer_handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, PUBLICKEYBYTES);
+
+ fastd_tristate_t verified = fastd_verify_peer(peer, sock, local_addr, remote_addr, method, &verify_data, sizeof(verify_data));
+
+ if (!verified.set)
+ /* async verify */
+ return false;
+
+ if (!verified.state) {
+ pr_debug("ignoring handshake from %P[%I] (verification failed)", peer, remote_addr);
+ fastd_peer_delete(peer);
+ return false;
+ }
+
+ return true;
+}
+
void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr,
fastd_peer_t *peer, const fastd_handshake_t *handshake, const fastd_method_info_t *method) {
fastd_protocol_ec25519_fhmqvc_maintenance();
@@ -546,7 +583,7 @@ void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const
return;
case ENOENT:
- peer = add_temporary(remote_addr, handshake->records[RECORD_SENDER_KEY].data);
+ peer = add_temporary(sock, remote_addr, handshake->records[RECORD_SENDER_KEY].data);
if (peer)
break;
@@ -557,9 +594,8 @@ void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const
}
}
- if (fastd_peer_is_temporary(peer) && !fastd_peer_verify_temporary(peer, local_addr, remote_addr)) {
- pr_debug("ignoring handshake from %P[%I] (verification failed)", peer, remote_addr);
- fastd_peer_delete(peer);
+ if (!has_field(handshake, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES)) {
+ pr_debug("received handshake without sender handshake key from %P[%I]", peer, remote_addr);
return;
}
@@ -580,9 +616,9 @@ void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const
}
}
- if (!has_field(handshake, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES)) {
- pr_debug("received handshake without sender handshake key from %P[%I]", peer, remote_addr);
- return;
+ if (fastd_peer_is_temporary(peer)) {
+ if (!handle_temporary(sock, local_addr, remote_addr, peer, handshake, method))
+ return;
}
aligned_int256_t peer_handshake_key;
@@ -599,7 +635,7 @@ void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const
peer->last_handshake_response_timeout = fastd_in_seconds(conf.min_handshake_interval);
peer->last_handshake_response_address = *remote_addr;
- respond_handshake(sock, local_addr, remote_addr, peer, &ctx.protocol_state->handshake_key, &peer_handshake_key, method);
+ respond_handshake(sock, local_addr, remote_addr, peer, &peer_handshake_key, method);
return;
}
@@ -651,3 +687,15 @@ void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const
pr_debug("received handshake reply with unknown type %u from %P[%I]", handshake->type, peer, remote_addr);
}
}
+
+void fastd_protocol_ec25519_fhmqvc_handle_verify_return(fastd_peer_t *peer, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr,
+ const fastd_method_info_t *method, const void *protocol_data, bool ok) {
+ if (!ok)
+ return;
+
+ const verify_data_t *data = protocol_data;
+
+ peer->last_handshake_response_timeout = fastd_in_seconds(conf.min_handshake_interval);
+ peer->last_handshake_response_address = *remote_addr;
+ respond_handshake(sock, local_addr, remote_addr, peer, &data->peer_handshake_key, method);
+}
diff --git a/src/types.h b/src/types.h
index 8a80d19..4510be2 100644
--- a/src/types.h
+++ b/src/types.h
@@ -89,10 +89,6 @@ typedef enum fastd_loglevel {
LL_DEBUG2,
} fastd_loglevel_t;
-typedef enum fastd_async_type {
- ASYNC_TYPE_RESOLVE_RETURN,
-} fastd_async_type_t;
-
typedef struct fastd_buffer fastd_buffer_t;
@@ -134,8 +130,6 @@ typedef struct fastd_string_stack fastd_string_stack_t;
typedef struct fastd_shell_command fastd_shell_command_t;
typedef struct fastd_shell_env fastd_shell_env_t;
-typedef struct fastd_async_resolve_return fastd_async_resolve_return_t;
-
typedef union fastd_block128 {
uint8_t b[16];
diff --git a/src/verify.c b/src/verify.c
new file mode 100644
index 0000000..fb592bd
--- /dev/null
+++ b/src/verify.c
@@ -0,0 +1,111 @@
+/*
+ Copyright (c) 2012-2014, Matthias Schiffer <mschiffer@universe-factory.net>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "verify.h"
+#include "async.h"
+#include "shell.h"
+
+#include <pthread.h>
+
+
+static bool do_verify(const fastd_shell_env_t *env) {
+ int ret;
+ if (!fastd_shell_command_exec_sync(&conf.on_verify, env, &ret))
+ return false;
+
+ if (WIFSIGNALED(ret)) {
+ pr_error("verify command exited with signal %i", WTERMSIG(ret));
+ return false;
+ }
+ else if (WEXITSTATUS(ret)) {
+ pr_debug("verify command exited with status %i", WEXITSTATUS(ret));
+ return false;
+ }
+
+ return true;
+}
+
+typedef struct verify_arg {
+ fastd_shell_env_t *env;
+ size_t ret_len;
+ fastd_async_verify_return_t ret;
+} verify_arg_t;
+
+static void * do_verify_thread(void *p) {
+ verify_arg_t *arg = p;
+
+ arg->ret.ok = do_verify(arg->env);
+ fastd_shell_env_free(arg->env);
+
+ fastd_async_enqueue(ASYNC_TYPE_VERIFY_RETURN, &arg->ret, arg->ret_len);
+
+ free(arg);
+
+ return NULL;
+}
+
+fastd_tristate_t fastd_verify_peer(fastd_peer_t *peer, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, const fastd_method_info_t *method, const void *data, size_t data_len) {
+ if (!fastd_shell_command_isset(&conf.on_verify))
+ exit_bug("tried to verify peer without on-verify command");
+
+ fastd_peer_set_verifying(peer);
+
+ fastd_shell_env_t *env = fastd_shell_env_alloc();
+ fastd_peer_set_shell_env(env, peer, local_addr, remote_addr);
+
+ if (conf.on_verify.sync) {
+ bool ret = do_verify(env);
+ fastd_shell_env_free(env);
+ fastd_peer_set_verified(peer, ret);
+ return (fastd_tristate_t){.set = true, .state = ret};
+ }
+ else {
+ verify_arg_t *arg = calloc(1, sizeof(verify_arg_t) + data_len);
+
+ arg->env = env;
+ arg->ret_len = sizeof(fastd_async_verify_return_t) + data_len;
+
+ arg->ret.peer_id = peer->id;
+ arg->ret.method = method;
+ arg->ret.sock = sock;
+ arg->ret.local_addr = *local_addr;
+ arg->ret.remote_addr = *remote_addr;
+ memcpy(arg->ret.protocol_data, data, data_len);
+
+ pthread_t thread;
+ if ((errno = pthread_create(&thread, NULL, do_verify_thread, arg)) != 0) {
+ pr_error_errno("unable to create verify thread");
+
+ fastd_shell_env_free(env);
+ free(arg);
+
+ return (fastd_tristate_t){.set = true, .state = false};
+ }
+
+ pthread_detach(thread);
+ return (fastd_tristate_t){.set = false};
+ }
+}
diff --git a/src/verify.h b/src/verify.h
new file mode 100644
index 0000000..6f1b525
--- /dev/null
+++ b/src/verify.h
@@ -0,0 +1,33 @@
+/*
+ Copyright (c) 2012-2014, Matthias Schiffer <mschiffer@universe-factory.net>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#pragma once
+
+
+#include "types.h"
+
+
+fastd_tristate_t fastd_verify_peer(fastd_peer_t *peer, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, const fastd_method_info_t *method, const void *data, size_t data_len);