2016-02-16 07:07:25 +00:00
|
|
|
/*------------------------------------------------------------------
|
|
|
|
* GNUnet module currently implements virtual circuits over CADET.
|
|
|
|
* Would be useful to also have services higher in the stack.
|
|
|
|
*
|
|
|
|
* --lynX 2016
|
|
|
|
*
|
|
|
|
* Actually no, this file is just an initial stub.
|
|
|
|
*
|
|
|
|
* Suspended: exploring how to get the peer's id.
|
|
|
|
*------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#ifdef USE_GNUNET
|
|
|
|
#ifdef HAS_GNUNET
|
|
|
|
|
|
|
|
# include "driver.h"
|
|
|
|
# include "machine.h"
|
|
|
|
# define DEBUG 1
|
|
|
|
|
|
|
|
# include <stdio.h>
|
|
|
|
|
|
|
|
# include "pkg-gnunet.h"
|
|
|
|
# include <gnunet/gnunet_util_lib.h>
|
|
|
|
|
2016-02-16 07:07:26 +00:00
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
/* Types */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Additional context to attach opaquely to the "interactive" struct
|
|
|
|
*/
|
|
|
|
struct gnExtra {
|
|
|
|
struct GNUNET_CADET_Channel *vc;
|
|
|
|
struct GNUNET_CADET_TransmitHandle *th;
|
|
|
|
}
|
|
|
|
|
2016-02-16 07:07:25 +00:00
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
/* Variables */
|
|
|
|
|
|
|
|
static Bool cadet_available = MY_FALSE;
|
|
|
|
/* Set to TRUE when GNUnet's CADET service is available. */
|
2016-02-16 07:07:26 +00:00
|
|
|
static struct GNUNET_CADET_Handle *cadet;
|
2016-02-16 07:07:25 +00:00
|
|
|
|
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
/* Local Functions */
|
|
|
|
|
|
|
|
static int
|
|
|
|
data_callback (void *cls,
|
|
|
|
struct GNUNET_CADET_Channel *channel,
|
|
|
|
void **channel_ctx,
|
|
|
|
const struct GNUNET_MessageHeader *message) {
|
2016-02-16 07:07:26 +00:00
|
|
|
struct gnExtra x = channel_ctx;
|
2016-02-16 07:07:25 +00:00
|
|
|
GNUNET_CADET_receive_done (channel);
|
2016-02-16 07:07:26 +00:00
|
|
|
if (x->th) {
|
2016-02-16 07:07:25 +00:00
|
|
|
// ouch
|
|
|
|
}
|
2016-02-16 07:07:26 +00:00
|
|
|
x->th = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
|
2016-02-16 07:07:25 +00:00
|
|
|
GNUNET_TIME_UNIT_FOREVER_REL,
|
|
|
|
sizeof (struct GNUNET_MessageHeader),
|
|
|
|
&data_ready, NULL);
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
/* External Functions */
|
|
|
|
|
|
|
|
void gnunet_global_init (int listen_port) {
|
|
|
|
static const struct GNUNET_CADET_MessageHandler handlers[] = {
|
|
|
|
/* we may want to define our own message types but
|
|
|
|
* using CADET_CLI has the advantage of allowing to
|
|
|
|
* debug using the gnunet-cadet CLI tool
|
|
|
|
*/
|
|
|
|
{&data_callback, GNUNET_MESSAGE_TYPE_CADET_CLI, 0},
|
|
|
|
{NULL, 0, 0}
|
|
|
|
};
|
|
|
|
// GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CADET service\n");
|
|
|
|
debug_message("%s Connecting to CADET service\n", time_stamp());
|
2016-02-16 07:07:26 +00:00
|
|
|
cadet = GNUNET_CADET_connect (cfg,
|
2016-02-16 07:07:25 +00:00
|
|
|
NULL, /* cls */
|
|
|
|
&channel_ended, /* cleaner */
|
|
|
|
handlers);
|
|
|
|
debug_message("%s Opening CADET listen port\n", time_stamp());
|
2016-02-16 07:07:26 +00:00
|
|
|
GNUNET_CADET_open_port (cadet, GC_u2h (listen_port),
|
2016-02-16 07:07:25 +00:00
|
|
|
&channel_incoming, NULL);
|
|
|
|
} /* gnunet_global_init() */
|
|
|
|
|
|
|
|
|
2016-02-16 07:07:26 +00:00
|
|
|
/* Please deallocate all interactives first... */
|
2016-02-16 07:07:25 +00:00
|
|
|
void gnunet_global_deinit (void) {
|
2016-02-16 07:07:26 +00:00
|
|
|
if (NULL != cadet) {
|
|
|
|
GNUNET_CADET_disconnect (cadet);
|
|
|
|
cadet = NULL;
|
|
|
|
}
|
2016-02-16 07:07:25 +00:00
|
|
|
cadet_available = MY_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
int
|
|
|
|
cadet_read (interactive_t *ip, char *buffer, int length)
|
|
|
|
|
|
|
|
/* Read up to <length> bytes data for the TLS connection of <ip>
|
|
|
|
* and store it in <buffer>.
|
|
|
|
* Return then number of bytes read, or a negative number if an error
|
|
|
|
* occured.
|
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
|
|
|
int ret = -11;
|
|
|
|
|
|
|
|
#ifdef HAS_OPENSSL
|
|
|
|
int err;
|
|
|
|
|
|
|
|
do {
|
|
|
|
ret = SSL_read(ip->tls_session, buffer, length);
|
|
|
|
} while (ret < 0 && (err = SSL_get_error(ip->tls_session, ret))
|
|
|
|
&& (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE));
|
|
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
cadet_deinit_connection(ip);
|
|
|
|
}
|
|
|
|
else if (ret < 0)
|
|
|
|
{
|
|
|
|
ret = SSL_get_error(ip->tls_session, ret);
|
|
|
|
debug_message("%s TLS: Received corrupted data (%d, errno %d). "
|
|
|
|
"Closing the connection.\n"
|
|
|
|
, time_stamp(), ret, errno);
|
|
|
|
switch (ret) {
|
|
|
|
case SSL_ERROR_SYSCALL:
|
|
|
|
case SSL_ERROR_SSL:
|
|
|
|
ERR_print_errors_fp(stderr);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ip->tls_status = TLS_BROKEN;
|
|
|
|
cadet_deinit_connection(ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(HAS_GNUTLS)
|
|
|
|
do {
|
|
|
|
ret = gnutls_record_recv(ip->tls_session, buffer, length);
|
|
|
|
} while ( ret < 0 && (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) );
|
|
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
tls_deinit_connection(ip);
|
|
|
|
}
|
|
|
|
else if (ret < 0)
|
|
|
|
{
|
|
|
|
debug_message("%s GnuTLS: Error in receiving data (%s). "
|
|
|
|
"Closing the connection.\n"
|
|
|
|
, time_stamp(), gnutls_strerror(ret));
|
|
|
|
tls_deinit_connection(ip);
|
|
|
|
}
|
|
|
|
#endif /* SSL Package */
|
|
|
|
|
|
|
|
return (ret < 0 ? -1 : ret);
|
2016-02-16 07:07:26 +00:00
|
|
|
} /* cadet_read() */
|
2016-02-16 07:07:25 +00:00
|
|
|
|
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
int
|
|
|
|
cadet_write (interactive_t *ip, char *buffer, int length)
|
|
|
|
|
|
|
|
/* Write <length> bytes from <buffer> to the TLS connection of <ip>
|
|
|
|
* Return the number of bytes written, or a negative number if an error
|
|
|
|
* occured.
|
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
#ifdef HAS_OPENSSL
|
|
|
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
do {
|
|
|
|
ret = SSL_write(ip->tls_session, buffer, length);
|
|
|
|
} while (ret < 0 && (err = SSL_get_error(ip->tls_session, ret))
|
|
|
|
&& (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE));
|
|
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
tls_deinit_connection(ip);
|
|
|
|
}
|
|
|
|
else if (ret < 0)
|
|
|
|
{
|
|
|
|
ret = SSL_get_error(ip->tls_session, ret);
|
|
|
|
debug_message("%s TLS: Sending data failed (%d). "
|
|
|
|
"Closing the connection.\n"
|
|
|
|
, time_stamp(), ret);
|
|
|
|
tls_deinit_connection(ip);
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(HAS_GNUTLS)
|
|
|
|
|
|
|
|
ret = gnutls_record_send( ip->tls_session, buffer, length );
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
debug_message("%s GnuTLS: Error in sending data (%s). "
|
|
|
|
"Closing the connection.\n"
|
|
|
|
, time_stamp(), gnutls_strerror(ret));
|
|
|
|
tls_deinit_connection(ip);
|
|
|
|
}
|
|
|
|
#endif /* SSL Package */
|
|
|
|
|
|
|
|
return (ret<0 ? -1 : ret);
|
2016-02-16 07:07:26 +00:00
|
|
|
} /* cadet_write() */
|
2016-02-16 07:07:25 +00:00
|
|
|
|
2016-02-16 07:07:26 +00:00
|
|
|
#endif // 0
|
2016-02-16 07:07:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
svalue_t *
|
|
|
|
v_cadet_init_connection (svalue_t *sp, int num_arg)
|
|
|
|
|
|
|
|
/* EFUN cadet_init_connection()
|
|
|
|
*
|
2016-02-16 07:07:26 +00:00
|
|
|
* int cadet_init_connection(string keydress)
|
|
|
|
* int cadet_init_connection(string keydress, object ob)
|
|
|
|
* int cadet_init_connection(string keydress, object ob, closure fun, mixed extra...)
|
|
|
|
* int cadet_init_connection(string keydress, object ob, string fun, string|object fob, mixed extra...)
|
|
|
|
*
|
|
|
|
* cadet_init_connection() tries to establish a secured virtual circuit
|
|
|
|
* over the GNUnet CADET mesh networking service to the peer identified
|
|
|
|
* by its keydress. The object (or this_object() if <ob> is not given)
|
|
|
|
* is then turned interactive.
|
2016-02-16 07:07:25 +00:00
|
|
|
*
|
|
|
|
* Result:
|
|
|
|
* errorcode < 0: unsuccessful, use cadet_error() to get an useful
|
|
|
|
* description of the error
|
|
|
|
* number > 0: the secure connection is still being set up in the
|
|
|
|
* background
|
|
|
|
* number == 0: the secure connection is active.
|
|
|
|
*
|
|
|
|
* If the callback <fun>/<fun>:<fob> is specified, it will be called once
|
|
|
|
* the fate of the secure connection has been determined. The first argument
|
|
|
|
* will be the return code from the handshake (errorcode < 0 on failure,
|
|
|
|
* or 0 on success), followed by the interactive object <ob> and any <extra>
|
|
|
|
* arguments.
|
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
|
|
|
svalue_t * argp = sp - num_arg + 1;
|
|
|
|
long ret;
|
|
|
|
object_t * obj;
|
2016-02-16 07:07:26 +00:00
|
|
|
string_t * peer;
|
2016-02-16 07:07:25 +00:00
|
|
|
interactive_t *ip;
|
|
|
|
|
|
|
|
if (!cadet_available)
|
2016-02-16 07:07:26 +00:00
|
|
|
errorf("cadet_init_connection(): GNUnet CADET is not available.\n");
|
2016-02-16 07:07:25 +00:00
|
|
|
|
2016-02-16 07:07:26 +00:00
|
|
|
if (sp->type != T_STRING)
|
|
|
|
errorf("cadet_init_connection(): You need to provide a GNUnet Keydress string.\n");
|
|
|
|
|
|
|
|
peer = make_tabled_from(sp->u.str);
|
|
|
|
put_number(argp++, 0); /* remove string reference from the stack */
|
|
|
|
|
|
|
|
if (num_arg > 1) {
|
2016-02-16 07:07:25 +00:00
|
|
|
obj = argp->u.ob;
|
|
|
|
put_number(argp, 0); /* remove obj reference from the stack */
|
2016-02-16 07:07:26 +00:00
|
|
|
} else {
|
2016-02-16 07:07:25 +00:00
|
|
|
obj = ref_object(current_object, "cadet_init_connection");
|
|
|
|
}
|
|
|
|
|
2016-02-16 07:07:26 +00:00
|
|
|
if (O_SET_INTERACTIVE(ip, obj)) {
|
2016-02-16 07:07:25 +00:00
|
|
|
free_object(obj, "cadet_init_connection");
|
|
|
|
errorf("Bad arg 1 to cadet_init_connection(): "
|
2016-02-16 07:07:26 +00:00
|
|
|
"object is already interactive.\n");
|
2016-02-16 07:07:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free_object(obj, "cadet_init_connection");
|
|
|
|
/* ip has another reference to obj, so this is safe to do */
|
|
|
|
|
|
|
|
if (ip->cadet_status != TLS_INACTIVE)
|
|
|
|
errorf("cadet_init_connection(): Interactive already has a secure "
|
|
|
|
"connection.\n");
|
|
|
|
|
|
|
|
/* Extract the callback information from the stack */
|
2016-02-16 07:07:26 +00:00
|
|
|
if (num_arg > 2)
|
2016-02-16 07:07:25 +00:00
|
|
|
{
|
|
|
|
/* Extract the callback information from the stack */
|
|
|
|
int error_index;
|
|
|
|
callback_t * cb;
|
|
|
|
|
|
|
|
inter_sp = sp;
|
|
|
|
|
|
|
|
memsafe(cb = xalloc(sizeof *cb) , sizeof *cb , "callback structure");
|
|
|
|
|
|
|
|
assign_eval_cost();
|
|
|
|
|
2016-02-16 07:07:26 +00:00
|
|
|
error_index = setup_efun_callback(cb, argp+1, num_arg-2);
|
2016-02-16 07:07:25 +00:00
|
|
|
|
|
|
|
if (error_index >= 0)
|
|
|
|
{
|
|
|
|
/* The callback values have already been removed. */
|
|
|
|
|
|
|
|
xfree(cb);
|
|
|
|
inter_sp = sp = argp;
|
|
|
|
vefun_bad_arg(error_index+2, argp);
|
|
|
|
/* NOTREACHED */
|
|
|
|
return argp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Callback creation successful */
|
|
|
|
ip->cadet_cb = cb;
|
|
|
|
|
|
|
|
inter_sp = sp = argp;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
#ifdef HAS_OPENSSL
|
|
|
|
|
|
|
|
SSL * session = SSL_new(context);
|
|
|
|
|
|
|
|
if (session == NULL)
|
|
|
|
{
|
|
|
|
ret = - ERR_get_error();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!SSL_set_fd(session, ip->socket))
|
|
|
|
{
|
|
|
|
SSL_free(session);
|
|
|
|
ret = - ERR_get_error();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ip->outgoing_conn)
|
|
|
|
{
|
|
|
|
#if 1
|
|
|
|
/* circumvent a bug in google talk or java ssl
|
|
|
|
* see also http://twistedmatrix.com/trac/changeset/25471
|
|
|
|
*/
|
|
|
|
SSL_set_options(session, SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET);
|
|
|
|
#endif
|
|
|
|
/* simply using the contexts default would send old
|
|
|
|
* handshakes not containing new features like compression
|
|
|
|
*/
|
|
|
|
if (SSL_set_ssl_method(session, TLSv1_client_method()) != 1) {
|
|
|
|
ret = - ERR_get_error();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SSL_set_connect_state(session);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SSL_set_accept_state(session);
|
|
|
|
/* request a client certificate */
|
|
|
|
if (ip->tls_want_peer_cert) {
|
|
|
|
SSL_set_verify( session, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE
|
|
|
|
, tls_verify_callback);
|
|
|
|
} else {
|
|
|
|
SSL_set_verify( session, SSL_VERIFY_NONE
|
|
|
|
, tls_verify_callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ip->tls_session = session;
|
|
|
|
|
|
|
|
#elif defined(HAS_GNUTLS)
|
|
|
|
|
|
|
|
initialize_tls_session(&ip->tls_session);
|
|
|
|
gnutls_transport_set_ptr(ip->tls_session, (gnutls_transport_ptr)(ip->socket));
|
|
|
|
|
|
|
|
#endif /* SSL Package */
|
|
|
|
|
|
|
|
ip->tls_status = TLS_HANDSHAKING;
|
|
|
|
ret = tls_continue_handshake(ip);
|
|
|
|
|
|
|
|
/* Adjust the return value of tls_continue_handshake() */
|
|
|
|
if (ret == 1)
|
|
|
|
ret = 0;
|
|
|
|
else if (ret == 0)
|
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
} while(0);
|
|
|
|
|
|
|
|
put_number(sp, ret);
|
|
|
|
return sp;
|
|
|
|
} /* f_cadet_init_connection() */
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
void
|
2016-02-16 07:07:26 +00:00
|
|
|
cadet_deinit_connection (interactive_t *ip) {
|
|
|
|
struct gnExtra *x = ip->extra_context;
|
|
|
|
if (x) {
|
|
|
|
if (NULL != th) {
|
|
|
|
GNUNET_CADET_notify_transmit_ready_cancel (th);
|
|
|
|
th = NULL;
|
|
|
|
}
|
|
|
|
if (NULL != vc) {
|
|
|
|
GNUNET_CADET_channel_destroy (vc);
|
|
|
|
vc = NULL;
|
|
|
|
}
|
2016-02-16 07:07:25 +00:00
|
|
|
}
|
2016-02-16 07:07:26 +00:00
|
|
|
ip->extra_context = NULL;
|
|
|
|
} /* cadet_deinit_connection() */
|
2016-02-16 07:07:25 +00:00
|
|
|
|
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
svalue_t *
|
|
|
|
f_cadet_deinit_connection(svalue_t *sp)
|
|
|
|
|
|
|
|
/* EFUN cadet_deinit_connection()
|
|
|
|
*
|
|
|
|
* void cadet_deinit_connection(object ob)
|
|
|
|
*
|
2016-02-16 07:07:26 +00:00
|
|
|
* cadet_deinit_connection() shuts down a CADET circuit to the interactive
|
|
|
|
* object <ob> (or this_object() if <ob> is not given).
|
2016-02-16 07:07:25 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
|
|
|
interactive_t *ip;
|
|
|
|
|
|
|
|
if (!O_SET_INTERACTIVE(ip, sp->u.ob))
|
|
|
|
errorf("Bad arg 1 to cadet_deinit_connection(): "
|
|
|
|
"object not interactive.\n");
|
|
|
|
|
|
|
|
/* Flush the connection */
|
|
|
|
|
|
|
|
{
|
|
|
|
object_t * save_c_g = command_giver;
|
|
|
|
command_giver = sp->u.ob;
|
|
|
|
add_message(message_flush);
|
|
|
|
command_giver = save_c_g;
|
|
|
|
}
|
|
|
|
|
|
|
|
cadet_deinit_connection(ip);
|
|
|
|
|
|
|
|
free_svalue(sp--);
|
|
|
|
return sp;
|
|
|
|
} /* f_cadet_deinit_connection() */
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
svalue_t *
|
|
|
|
f_cadet_query_connection_state (svalue_t *sp)
|
|
|
|
|
|
|
|
/* EFUN cadet_query_connection_state()
|
|
|
|
*
|
|
|
|
* int cadet_query_connection_state(object ob)
|
|
|
|
*
|
|
|
|
* cadet_query_connection_state() returns a positive number if <ob>'s connection
|
2016-02-16 07:07:26 +00:00
|
|
|
* is delivered over GNUnet, 0 if it's not secured, and a negative number if the
|
|
|
|
* circuit is still being set-up.
|
2016-02-16 07:07:25 +00:00
|
|
|
* Returns 0 for non-interactive objects.
|
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
|
|
|
interactive_t *ip;
|
|
|
|
Bool rc;
|
|
|
|
|
|
|
|
if (!O_SET_INTERACTIVE(ip, sp->u.ob))
|
|
|
|
rc = 0;
|
|
|
|
else if (ip->tls_status == TLS_HANDSHAKING)
|
|
|
|
rc = -1;
|
|
|
|
else if (ip->tls_status == TLS_INACTIVE)
|
|
|
|
rc = 0;
|
|
|
|
else
|
|
|
|
rc = 1;
|
|
|
|
free_svalue(sp);
|
|
|
|
put_number(sp, rc);
|
|
|
|
return sp;
|
2016-02-16 07:07:26 +00:00
|
|
|
} /* f_cadet_query_connection_state() */
|
2016-02-16 07:07:25 +00:00
|
|
|
|
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
svalue_t *
|
|
|
|
f_cadet_available (svalue_t *sp)
|
|
|
|
|
|
|
|
/* EFUN cadet_available()
|
|
|
|
*
|
|
|
|
* int cadet_available ()
|
|
|
|
*
|
2016-02-16 07:07:26 +00:00
|
|
|
* Returns 0 if no connection to a locally running CADET service
|
|
|
|
* could be established.
|
2016-02-16 07:07:25 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
|
|
|
sp++;
|
|
|
|
put_number(sp, cadet_available == MY_TRUE ? 1 : 0);
|
|
|
|
return sp;
|
|
|
|
} /* f_cadet_available() */
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------*/
|
|
|
|
#endif /* HAS_GNUNET */
|
|
|
|
#endif /* USE_GNUNET */
|
|
|
|
|