/*------------------------------------------------------------------ * 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 # include "pkg-gnunet.h" # include /*---------------------------------------------------------------*/ /* Types */ /** * Additional context to attach opaquely to the "interactive" struct */ struct gnExtra { struct GNUNET_CADET_Channel *vc; struct GNUNET_CADET_TransmitHandle *th; } /*---------------------------------------------------------------*/ /* Variables */ static Bool cadet_available = MY_FALSE; /* Set to TRUE when GNUnet's CADET service is available. */ static struct GNUNET_CADET_Handle *cadet; /*---------------------------------------------------------------*/ /* Local Functions */ static int data_callback (void *cls, struct GNUNET_CADET_Channel *channel, void **channel_ctx, const struct GNUNET_MessageHeader *message) { struct gnExtra x = channel_ctx; GNUNET_CADET_receive_done (channel); if (x->th) { // ouch } x->th = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO, 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()); cadet = GNUNET_CADET_connect (cfg, NULL, /* cls */ &channel_ended, /* cleaner */ handlers); debug_message("%s Opening CADET listen port\n", time_stamp()); GNUNET_CADET_open_port (cadet, GC_u2h (listen_port), &channel_incoming, NULL); } /* gnunet_global_init() */ /* Please deallocate all interactives first... */ void gnunet_global_deinit (void) { if (NULL != cadet) { GNUNET_CADET_disconnect (cadet); cadet = NULL; } cadet_available = MY_FALSE; } #if 0 /*---------------------------------------------------------------*/ int cadet_read (interactive_t *ip, char *buffer, int length) /* Read up to bytes data for the TLS connection of * and store it in . * 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); } /* cadet_read() */ /*---------------------------------------------------------------*/ int cadet_write (interactive_t *ip, char *buffer, int length) /* Write bytes from to the TLS connection of * 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); } /* cadet_write() */ #endif // 0 /*---------------------------------------------------------------*/ svalue_t * v_cadet_init_connection (svalue_t *sp, int num_arg) /* EFUN cadet_init_connection() * * 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 is not given) * is then turned interactive. * * 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 /: 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 and any * arguments. */ { svalue_t * argp = sp - num_arg + 1; long ret; object_t * obj; string_t * peer; interactive_t *ip; if (!cadet_available) errorf("cadet_init_connection(): GNUnet CADET is not available.\n"); 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) { obj = argp->u.ob; put_number(argp, 0); /* remove obj reference from the stack */ } else { obj = ref_object(current_object, "cadet_init_connection"); } if (O_SET_INTERACTIVE(ip, obj)) { free_object(obj, "cadet_init_connection"); errorf("Bad arg 1 to cadet_init_connection(): " "object is already interactive.\n"); } 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 */ if (num_arg > 2) { /* 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(); error_index = setup_efun_callback(cb, argp+1, num_arg-2); 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 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; } } ip->extra_context = NULL; } /* cadet_deinit_connection() */ /*---------------------------------------------------------------*/ svalue_t * f_cadet_deinit_connection(svalue_t *sp) /* EFUN cadet_deinit_connection() * * void cadet_deinit_connection(object ob) * * cadet_deinit_connection() shuts down a CADET circuit to the interactive * object (or this_object() if is not given). */ { 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 's connection * is delivered over GNUnet, 0 if it's not secured, and a negative number if the * circuit is still being set-up. * 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; } /* f_cadet_query_connection_state() */ /*---------------------------------------------------------------*/ svalue_t * f_cadet_available (svalue_t *sp) /* EFUN cadet_available() * * int cadet_available () * * Returns 0 if no connection to a locally running CADET service * could be established. */ { sp++; put_number(sp, cadet_available == MY_TRUE ? 1 : 0); return sp; } /* f_cadet_available() */ /*---------------------------------------------------------------*/ #endif /* HAS_GNUNET */ #endif /* USE_GNUNET */