diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2012-07-27 17:54:08 +0200 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2012-07-27 17:54:08 +0200 |
commit | 782e01f17798478322f7634c43d35653e92c2b2a (patch) | |
tree | 9babde108b57ca7a5b1014e4b5e2f357805ab8a4 /src/plugins/relay | |
parent | 32b8f345673f5eb736a27090e98de808f6e7fda2 (diff) | |
download | weechat-782e01f17798478322f7634c43d35653e92c2b2a.zip |
relay: add support of SSL (for irc and weechat protocols), new option relay.network.ssl_cert_key (task #12044)
Diffstat (limited to 'src/plugins/relay')
-rw-r--r-- | src/plugins/relay/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/relay/Makefile.am | 2 | ||||
-rw-r--r-- | src/plugins/relay/irc/relay-irc.c | 20 | ||||
-rw-r--r-- | src/plugins/relay/relay-buffer.c | 50 | ||||
-rw-r--r-- | src/plugins/relay/relay-client.c | 386 | ||||
-rw-r--r-- | src/plugins/relay/relay-client.h | 10 | ||||
-rw-r--r-- | src/plugins/relay/relay-command.c | 144 | ||||
-rw-r--r-- | src/plugins/relay/relay-completion.c | 13 | ||||
-rw-r--r-- | src/plugins/relay/relay-config.c | 102 | ||||
-rw-r--r-- | src/plugins/relay/relay-config.h | 5 | ||||
-rw-r--r-- | src/plugins/relay/relay-network.c | 163 | ||||
-rw-r--r-- | src/plugins/relay/relay-network.h | 39 | ||||
-rw-r--r-- | src/plugins/relay/relay-server.c | 36 | ||||
-rw-r--r-- | src/plugins/relay/relay-server.h | 8 | ||||
-rw-r--r-- | src/plugins/relay/relay.c | 42 | ||||
-rw-r--r-- | src/plugins/relay/relay.h | 1 | ||||
-rw-r--r-- | src/plugins/relay/weechat/relay-weechat-protocol.c | 16 | ||||
-rw-r--r-- | src/plugins/relay/weechat/relay-weechat-protocol.h | 9 |
18 files changed, 854 insertions, 193 deletions
diff --git a/src/plugins/relay/CMakeLists.txt b/src/plugins/relay/CMakeLists.txt index 19ac753b4..1084fe9b8 100644 --- a/src/plugins/relay/CMakeLists.txt +++ b/src/plugins/relay/CMakeLists.txt @@ -29,6 +29,7 @@ relay-command.c relay-command.h relay-completion.c relay-completion.h relay-config.c relay-config.h relay-info.c relay-info.h +relay-network.c relay-network.h relay-raw.c relay-raw.h relay-server.c relay-server.h relay-upgrade.c relay-upgrade.h) diff --git a/src/plugins/relay/Makefile.am b/src/plugins/relay/Makefile.am index 8734c159e..c359ad00b 100644 --- a/src/plugins/relay/Makefile.am +++ b/src/plugins/relay/Makefile.am @@ -45,6 +45,8 @@ relay_la_SOURCES = relay.c \ relay-config.h \ relay-info.c \ relay-info.h \ + relay-network.c \ + relay-network.h \ relay-raw.c \ relay-raw.h \ relay-server.c \ diff --git a/src/plugins/relay/irc/relay-irc.c b/src/plugins/relay/irc/relay-irc.c index 59641b1d4..0ea308269 100644 --- a/src/plugins/relay/irc/relay-irc.c +++ b/src/plugins/relay/irc/relay-irc.c @@ -221,9 +221,11 @@ relay_irc_signal_irc_in2_cb (void *data, const char *signal, if (weechat_relay_plugin->debug >= 2) { - weechat_printf (NULL, "%s: irc_in2: client: %s, data: %s", + weechat_printf (NULL, "%s: irc_in2: client: %s%s%s, data: %s", RELAY_PLUGIN_NAME, - client->protocol_args, + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT, ptr_msg); } @@ -344,9 +346,11 @@ relay_irc_signal_irc_outtags_cb (void *data, const char *signal, if (weechat_relay_plugin->debug >= 2) { - weechat_printf (NULL, "%s: irc_out: client: %s, message: %s", + weechat_printf (NULL, "%s: irc_out: client: %s%s%s, message: %s", RELAY_PLUGIN_NAME, - client->protocol_args, + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT, message); } @@ -757,8 +761,12 @@ relay_irc_recv_one_msg (struct t_relay_client *client, char *data) /* display debug message */ if (weechat_relay_plugin->debug >= 2) { - weechat_printf (NULL, "%s: recv from client %d: \"%s\"", - RELAY_PLUGIN_NAME, client->id, data); + weechat_printf (NULL, "%s: recv from client %s%s%s: \"%s\"", + RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT, + data); } /* display message in raw buffer */ diff --git a/src/plugins/relay/relay-buffer.c b/src/plugins/relay/relay-buffer.c index f02f32cf5..f0a32d563 100644 --- a/src/plugins/relay/relay-buffer.c +++ b/src/plugins/relay/relay-buffer.c @@ -47,7 +47,7 @@ void relay_buffer_refresh (const char *hotlist) { struct t_relay_client *ptr_client, *client_selected; - char str_color[256], status[64], date_start[128], date_end[128]; + char str_color[256], str_status[64], str_date_start[128], str_date_end[128]; char *str_recv, *str_sent; int i, length, line; struct tm *date_tmp; @@ -84,62 +84,60 @@ relay_buffer_refresh (const char *hotlist) weechat_config_string (relay_config_color_text), weechat_config_string (relay_config_color_text_bg)); - snprintf (status, sizeof (status), + snprintf (str_status, sizeof (str_status), "%s", _(relay_client_status_string[ptr_client->status])); - length = weechat_utf8_strlen_screen (status); + length = weechat_utf8_strlen_screen (str_status); if (length < 20) { for (i = 0; i < 20 - length; i++) { - strcat (status, " "); + strcat (str_status, " "); } } - date_start[0] = '\0'; + str_date_start[0] = '\0'; date_tmp = localtime (&(ptr_client->start_time)); if (date_tmp) { - strftime (date_start, sizeof (date_start), + strftime (str_date_start, sizeof (str_date_start), "%a, %d %b %Y %H:%M:%S", date_tmp); } - date_end[0] = '\0'; + str_date_end[0] = '-'; + str_date_end[1] = '\0'; if (ptr_client->end_time > 0) { date_tmp = localtime (&(ptr_client->end_time)); if (date_tmp) { - strftime (date_end, sizeof (date_end), + strftime (str_date_end, sizeof (str_date_end), "%a, %d %b %Y %H:%M:%S", date_tmp); } } - /* first line with status and start time */ + str_recv = weechat_string_format_size (ptr_client->bytes_recv); + str_sent = weechat_string_format_size (ptr_client->bytes_sent); + + /* first line with status, description and bytes recv/sent */ weechat_printf_y (relay_buffer, (line * 2) + 2, - _("%s%s[%s%s%s%s] %s (started on: %s%s%s%s)"), + _("%s%s[%s%s%s%s] %s, received: %s, sent: %s"), weechat_color(str_color), - (line == relay_buffer_selected_line) ? - "*** " : " ", + (line == relay_buffer_selected_line) ? "*** " : " ", weechat_color(weechat_config_string (relay_config_color_status[ptr_client->status])), - status, + str_status, weechat_color ("reset"), weechat_color (str_color), - ptr_client->address, - date_start, - (ptr_client->end_time > 0) ? ", " : "", - (ptr_client->end_time > 0) ? _("ended on: ") : "", - (ptr_client->end_time > 0) ? date_end : ""); + ptr_client->desc, + (str_recv) ? str_recv : "?", + (str_sent) ? str_sent : "?"); - /* second line with protocol and bytes recv/sent */ - str_recv = weechat_string_format_size (ptr_client->bytes_recv); - str_sent = weechat_string_format_size (ptr_client->bytes_sent); + /* second line with start/end time */ weechat_printf_y (relay_buffer, (line * 2) + 3, - _("%s%-26s id: %d, protocol: %s, received: %s, sent: %s"), + _("%s%-26s started on: %s, ended on: %s"), weechat_color(str_color), " ", - ptr_client->id, - relay_protocol_string[ptr_client->protocol], - (str_recv) ? str_recv : "?", - (str_sent) ? str_sent : "?"); + str_date_start, + str_date_end); + if (str_recv) free (str_recv); if (str_sent) diff --git a/src/plugins/relay/relay-client.c b/src/plugins/relay/relay-client.c index dbb0ac587..5076fa177 100644 --- a/src/plugins/relay/relay-client.c +++ b/src/plugins/relay/relay-client.c @@ -31,6 +31,10 @@ #include <sys/types.h> #include <sys/socket.h> +#ifdef HAVE_GNUTLS +#include <gnutls/gnutls.h> +#endif + #include "../weechat-plugin.h" #include "relay.h" #include "relay-client.h" @@ -38,6 +42,7 @@ #include "weechat/relay-weechat.h" #include "relay-config.h" #include "relay-buffer.h" +#include "relay-network.h" #include "relay-server.h" @@ -120,6 +125,95 @@ relay_client_search_by_id (int id) } /* + * relay_client_set_desc: set description for client + */ + +void +relay_client_set_desc (struct t_relay_client *client) +{ + char desc[512]; + + if (client->desc) + free (client->desc); + + snprintf (desc, sizeof (desc), + "%d/%s%s%s%s/%s", + client->id, + (client->ssl) ? "ssl." : "", + relay_protocol_string[client->protocol], + (client->protocol_args) ? "." : "", + (client->protocol_args) ? client->protocol_args : "", + client->address); + + client->desc = strdup (desc); +} + +/* + * relay_client_handshake_timer_cb: timer called to do the handshake with the + * client (for SSL connection only) + */ + +#ifdef HAVE_GNUTLS +int +relay_client_handshake_timer_cb (void *data, int remaining_calls) +{ + struct t_relay_client *client; + int rc; + + client = (struct t_relay_client *)data; + + rc = gnutls_handshake (client->gnutls_sess); + + if (rc == GNUTLS_E_SUCCESS) + { + /* handshake ok, set status to "connected" */ + weechat_unhook (client->hook_timer_handshake); + client->hook_timer_handshake = NULL; + relay_client_set_status (client, RELAY_STATUS_CONNECTED); + return WEECHAT_RC_OK; + } + + if (gnutls_error_is_fatal (rc)) + { + /* handshake error, disconnect client */ + weechat_printf (NULL, + _("%s%s: TLS handshake failed for client %s%s%s: " + "error %d %s"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT, + rc, + gnutls_strerror (rc)); + weechat_unhook (client->hook_timer_handshake); + client->hook_timer_handshake = NULL; + relay_client_set_status (client, RELAY_STATUS_DISCONNECTED); + return WEECHAT_RC_OK; + } + + if (remaining_calls == 0) + { + /* handshake timeout, disconnect client */ + weechat_printf (NULL, + _("%s%s: TLS handshake timeout for client %s%s%s"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT); + weechat_unhook (client->hook_timer_handshake); + client->hook_timer_handshake = NULL; + relay_client_set_status (client, RELAY_STATUS_DISCONNECTED); + return WEECHAT_RC_OK; + } + + /* handshake in progress, we will try again on next call to timer */ + return WEECHAT_RC_OK; +} +#endif + +/* * relay_client_recv_cb: read data from a client */ @@ -135,7 +229,17 @@ relay_client_recv_cb (void *arg_client, int fd) client = (struct t_relay_client *)arg_client; - num_read = recv (client->sock, buffer, sizeof (buffer) - 1, 0); + if (client->status != RELAY_STATUS_CONNECTED) + return WEECHAT_RC_OK; + +#ifdef HAVE_GNUTLS + if (client->ssl) + num_read = gnutls_record_recv (client->gnutls_sess, buffer, + sizeof (buffer) - 1); + else +#endif + num_read = recv (client->sock, buffer, sizeof (buffer) - 1, 0); + if (num_read > 0) { client->bytes_recv += num_read; @@ -155,18 +259,43 @@ relay_client_recv_cb (void *arg_client, int fd) } else { - if ((num_read == 0) - || ((errno != EAGAIN) && (errno != EWOULDBLOCK))) +#ifdef HAVE_GNUTLS + if (client->ssl) + { + if ((num_read == 0) + || ((num_read != GNUTLS_E_AGAIN) && (num_read != GNUTLS_E_INTERRUPTED))) + { + weechat_printf (NULL, + _("%s%s: reading data on socket for client %s%s%s: " + "error %d %s"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT, + num_read, + (num_read == 0) ? _("(connection closed by peer)") : + gnutls_strerror (num_read)); + relay_client_set_status (client, RELAY_STATUS_DISCONNECTED); + } + } + else +#endif { - weechat_printf (NULL, - _("%s%s: reading data on socket for client %d: " - "error %d %s"), - weechat_prefix ("error"), RELAY_PLUGIN_NAME, - client->id, - errno, - (num_read == 0) ? _("(connection closed by peer)") : - strerror (errno)); - relay_client_set_status (client, RELAY_STATUS_DISCONNECTED); + if ((num_read == 0) + || ((errno != EAGAIN) && (errno != EWOULDBLOCK))) + { + weechat_printf (NULL, + _("%s%s: reading data on socket for client %s%s%s: " + "error %d %s"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT, + errno, + (num_read == 0) ? _("(connection closed by peer)") : + strerror (errno)); + relay_client_set_status (client, RELAY_STATUS_DISCONNECTED); + } } } @@ -281,7 +410,13 @@ relay_client_send (struct t_relay_client *client, const char *data, } else { - num_sent = send (client->sock, data, data_size, 0); +#ifdef HAVE_GNUTLS + if (client->ssl) + num_sent = gnutls_record_send (client->gnutls_sess, data, data_size); + else +#endif + num_sent = send (client->sock, data, data_size, 0); + if (num_sent >= 0) { if (num_sent > 0) @@ -298,19 +433,52 @@ relay_client_send (struct t_relay_client *client, const char *data, } else if (num_sent < 0) { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) +#ifdef HAVE_GNUTLS + if (client->ssl) { - /* add message to queue (will be sent later) */ - relay_client_outqueue_add (client, data, data_size); + if ((num_sent == GNUTLS_E_AGAIN) + || (num_sent == GNUTLS_E_INTERRUPTED)) + { + /* add message to queue (will be sent later) */ + relay_client_outqueue_add (client, data, data_size); + } + else + { + weechat_printf (NULL, + _("%s%s: sending data to client %s%s%s: " + "error %d %s"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT, + num_sent, + gnutls_strerror (num_sent)); + relay_client_set_status (client, RELAY_STATUS_DISCONNECTED); + } } else +#endif { - weechat_printf (NULL, - _("%s%s: sending data to client %d: error %d %s"), - weechat_prefix ("error"), RELAY_PLUGIN_NAME, - client->id, - errno, strerror (errno)); - relay_client_set_status (client, RELAY_STATUS_DISCONNECTED); + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + { + /* add message to queue (will be sent later) */ + relay_client_outqueue_add (client, data, data_size); + } + else + { + weechat_printf (NULL, + _("%s%s: sending data to client %s%s%s: " + "error %d %s"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT, + errno, + strerror (errno)); + relay_client_set_status (client, RELAY_STATUS_DISCONNECTED); + } } } } @@ -341,8 +509,20 @@ relay_client_timer_cb (void *data, int remaining_calls) { while (ptr_client->outqueue) { - num_sent = send (ptr_client->sock, ptr_client->outqueue->data, - ptr_client->outqueue->data_size, 0); +#ifdef HAVE_GNUTLS + if (ptr_client->ssl) + { + num_sent = gnutls_record_send (ptr_client->gnutls_sess, + ptr_client->outqueue->data, + ptr_client->outqueue->data_size); + } + else +#endif + { + num_sent = send (ptr_client->sock, + ptr_client->outqueue->data, + ptr_client->outqueue->data_size, 0); + } if (num_sent >= 0) { if (num_sent > 0) @@ -380,21 +560,54 @@ relay_client_timer_cb (void *data, int remaining_calls) } else if (num_sent < 0) { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) +#ifdef HAVE_GNUTLS + if (ptr_client->ssl) { - /* we will retry later this client's queue */ - break; + if ((num_sent == GNUTLS_E_AGAIN) + || (num_sent == GNUTLS_E_INTERRUPTED)) + { + /* we will retry later this client's queue */ + break; + } + else + { + weechat_printf (NULL, + _("%s%s: sending data to client %s%s%s: " + "error %d %s"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_CLIENT, + ptr_client->desc, + RELAY_COLOR_CHAT, + num_sent, + gnutls_strerror (num_sent)); + relay_client_set_status (ptr_client, + RELAY_STATUS_DISCONNECTED); + } } else +#endif { - weechat_printf (NULL, - _("%s%s: sending data to client %d: error %d %s"), - weechat_prefix ("error"), - RELAY_PLUGIN_NAME, - ptr_client->id, - errno, strerror (errno)); - relay_client_set_status (ptr_client, - RELAY_STATUS_DISCONNECTED); + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + { + /* we will retry later this client's queue */ + break; + } + else + { + weechat_printf (NULL, + _("%s%s: sending data to client %s%s%s: " + "error %d %s"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_CLIENT, + ptr_client->desc, + RELAY_COLOR_CHAT, + errno, + strerror (errno)); + relay_client_set_status (ptr_client, + RELAY_STATUS_DISCONNECTED); + } } } } @@ -412,12 +625,18 @@ struct t_relay_client * relay_client_new (int sock, const char *address, struct t_relay_server *server) { struct t_relay_client *new_client; + struct t_config_option *ptr_option; new_client = malloc (sizeof (*new_client)); if (new_client) { new_client->id = (relay_clients) ? relay_clients->id + 1 : 1; + new_client->desc = NULL; new_client->sock = sock; + new_client->ssl = server->ssl; +#ifdef HAVE_GNUTLS + new_client->hook_timer_handshake = NULL; +#endif new_client->address = strdup ((address) ? address : "?"); new_client->status = RELAY_STATUS_CONNECTED; new_client->protocol = server->protocol; @@ -430,6 +649,36 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server) new_client->bytes_recv = 0; new_client->bytes_sent = 0; + relay_client_set_desc (new_client); + +#ifdef HAVE_GNUTLS + if (new_client->ssl) + { + if (!relay_network_init_ssl_cert_key_ok) + { + weechat_printf (NULL, + _("%s%s: warning: no SSL certificate/key found " + "(option relay.network.ssl_cert_key)"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME); + } + new_client->status = RELAY_STATUS_CONNECTING; + gnutls_init (&(new_client->gnutls_sess), GNUTLS_SERVER); + if (relay_gnutls_priority_cache) + gnutls_priority_set (new_client->gnutls_sess, *relay_gnutls_priority_cache); + gnutls_credentials_set (new_client->gnutls_sess, GNUTLS_CRD_CERTIFICATE, relay_gnutls_x509_cred); + gnutls_certificate_server_set_request (new_client->gnutls_sess, GNUTLS_CERT_IGNORE); + gnutls_transport_set_ptr (new_client->gnutls_sess, + (gnutls_transport_ptr) ((ptrdiff_t) new_client->sock)); + ptr_option = weechat_config_get ("weechat.network.gnutls_handshake_timeout"); + new_client->hook_timer_handshake = weechat_hook_timer (1000 / 10, + 0, + (ptr_option) ? + weechat_config_integer (ptr_option) * 10 : 30 * 10, + &relay_client_handshake_timer_cb, + new_client); + } +#endif + new_client->protocol_data = NULL; switch (new_client->protocol) { @@ -455,16 +704,12 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server) relay_clients = new_client; weechat_printf (NULL, - _("%s: new client from %s%s%s on port %d (id: %d, relaying: %s%s%s)"), + _("%s: new client on port %d: %s%s%s"), RELAY_PLUGIN_NAME, - RELAY_COLOR_CHAT_HOST, - new_client->address, - RELAY_COLOR_CHAT, server->port, - new_client->id, - relay_protocol_string[new_client->protocol], - (new_client->protocol_args) ? "." : "", - (new_client->protocol_args) ? new_client->protocol_args : ""); + RELAY_COLOR_CHAT_CLIENT, + new_client->desc, + RELAY_COLOR_CHAT); new_client->hook_fd = weechat_hook_fd (new_client->sock, 1, 0, 0, @@ -505,6 +750,7 @@ relay_client_new_with_infolist (struct t_infolist *infolist) if (new_client) { new_client->id = weechat_infolist_integer (infolist, "id"); + new_client->desc = NULL; new_client->sock = weechat_infolist_integer (infolist, "sock"); new_client->address = strdup (weechat_infolist_string (infolist, "address")); new_client->status = weechat_infolist_integer (infolist, "status"); @@ -529,6 +775,12 @@ relay_client_new_with_infolist (struct t_infolist *infolist) sscanf (weechat_infolist_string (infolist, "bytes_sent"), "%lu", &(new_client->bytes_sent)); + str = weechat_infolist_string (infolist, "desc"); + if (str) + new_client->desc = strdup (str); + else + relay_client_set_desc (new_client); + switch (new_client->protocol) { case RELAY_PROTOCOL_WEECHAT: @@ -596,26 +848,20 @@ relay_client_set_status (struct t_relay_client *client, { case RELAY_STATUS_AUTH_FAILED: weechat_printf (NULL, - _("%s%s: authentication failed with client %s%s%s (%s%s%s)"), + _("%s%s: authentication failed with client %s%s%s"), weechat_prefix ("error"), RELAY_PLUGIN_NAME, - RELAY_COLOR_CHAT_HOST, - client->address, - RELAY_COLOR_CHAT, - relay_protocol_string[client->protocol], - (client->protocol_args) ? "." : "", - (client->protocol_args) ? client->protocol_args : ""); + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT); break; case RELAY_STATUS_DISCONNECTED: weechat_printf (NULL, - _("%s: disconnected from client %s%s%s (%s%s%s)"), + _("%s: disconnected from client %s%s%s"), RELAY_PLUGIN_NAME, - RELAY_COLOR_CHAT_HOST, - client->address, - RELAY_COLOR_CHAT, - relay_protocol_string[client->protocol], - (client->protocol_args) ? "." : "", - (client->protocol_args) ? client->protocol_args : ""); + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT); break; default: break; @@ -623,8 +869,16 @@ relay_client_set_status (struct t_relay_client *client, if (client->sock >= 0) { +#ifdef HAVE_GNUTLS + if (client->ssl) + gnutls_bye (client->gnutls_sess, GNUTLS_SHUT_WR); +#endif close (client->sock); client->sock = -1; +#ifdef HAVE_GNUTLS + if (client->ssl) + gnutls_deinit (client->gnutls_sess); +#endif } } @@ -661,6 +915,10 @@ relay_client_free (struct t_relay_client *client) free (client->address); if (client->protocol_args) free (client->protocol_args); +#ifdef HAVE_GNUTLS + if (client->hook_timer_handshake) + weechat_unhook (client->hook_timer_handshake); +#endif if (client->hook_fd) weechat_unhook (client->hook_fd); if (client->protocol_data) @@ -754,8 +1012,16 @@ relay_client_add_to_infolist (struct t_infolist *infolist, if (!weechat_infolist_new_var_integer (ptr_item, "id", client->id)) return 0; + if (!weechat_infolist_new_var_string (ptr_item, "desc", client->desc)) + return 0; if (!weechat_infolist_new_var_integer (ptr_item, "sock", client->sock)) return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "ssl", client->ssl)) + return 0; +#ifdef HAVE_GNUTLS + if (!weechat_infolist_new_var_pointer (ptr_item, "hook_timer_handshake", client->hook_timer_handshake)) + return 0; +#endif if (!weechat_infolist_new_var_string (ptr_item, "address", client->address)) return 0; if (!weechat_infolist_new_var_integer (ptr_item, "status", client->status)) @@ -815,7 +1081,13 @@ relay_client_print_log () weechat_log_printf (""); weechat_log_printf ("[relay client (addr:0x%lx)]", ptr_client); weechat_log_printf (" id. . . . . . . . . . : %d", ptr_client->id); + weechat_log_printf (" desc. . . . . . . . . : '%s'", ptr_client->desc); weechat_log_printf (" sock. . . . . . . . . : %d", ptr_client->sock); + weechat_log_printf (" ssl . . . . . . . . . : %d", ptr_client->ssl); +#ifdef HAVE_GNUTLS + weechat_log_printf (" gnutls_sess . . . . . : 0x%lx", ptr_client->gnutls_sess); + weechat_log_printf (" hook_timer_handshake. : 0x%lx", ptr_client->hook_timer_handshake); +#endif weechat_log_printf (" address . . . . . . . : '%s'", ptr_client->address); weechat_log_printf (" status. . . . . . . . : %d (%s)", ptr_client->status, diff --git a/src/plugins/relay/relay-client.h b/src/plugins/relay/relay-client.h index b53002299..07a21b0b0 100644 --- a/src/plugins/relay/relay-client.h +++ b/src/plugins/relay/relay-client.h @@ -20,6 +20,10 @@ #ifndef __WEECHAT_RELAY_CLIENT_H #define __WEECHAT_RELAY_CLIENT_H 1 +#ifdef HAVE_GNUTLS +#include <gnutls/gnutls.h> +#endif + struct t_relay_server; /* relay status */ @@ -56,7 +60,13 @@ struct t_relay_client_outqueue struct t_relay_client { int id; /* unique id (diff. for each client) */ + char *desc; /* description, used for display */ int sock; /* socket for connection */ + int ssl; /* 1 if SSL is enabled */ +#ifdef HAVE_GNUTLS + gnutls_session_t gnutls_sess; /* gnutls session (only if SSL used) */ + struct t_hook *hook_timer_handshake; /* timer for doing gnutls handshake*/ +#endif char *address; /* string with IP address */ enum t_relay_status status; /* status (connecting, active,..) */ enum t_relay_protocol protocol; /* protocol (irc,..) */ diff --git a/src/plugins/relay/relay-command.c b/src/plugins/relay/relay-command.c index 16b4361ff..3d6a381c1 100644 --- a/src/plugins/relay/relay-command.c +++ b/src/plugins/relay/relay-command.c @@ -30,6 +30,7 @@ #include "relay-buffer.h" #include "relay-client.h" #include "relay-config.h" +#include "relay-network.h" #include "relay-raw.h" #include "relay-server.h" @@ -42,70 +43,80 @@ void relay_command_client_list (int full) { struct t_relay_client *ptr_client; - int i; char date_start[128], date_activity[128]; struct tm *date_tmp; + int num_found; - if (relay_clients) + num_found = 0; + for (ptr_client = relay_clients; ptr_client; + ptr_client = ptr_client->next_client) { - weechat_printf (NULL, ""); - weechat_printf (NULL, _("Clients for relay:")); - i = 1; - for (ptr_client = relay_clients; ptr_client; - ptr_client = ptr_client->next_client) + if (!full && RELAY_CLIENT_HAS_ENDED(ptr_client)) + continue; + + if (num_found == 0) { - date_start[0] = '\0'; - date_tmp = localtime (&(ptr_client->start_time)); - if (date_tmp) - { - strftime (date_start, sizeof (date_start), - "%a, %d %b %Y %H:%M:%S", date_tmp); - } + weechat_printf (NULL, ""); + weechat_printf (NULL, + (full) ? + _("Clients for relay:") : + _("Connected clients for relay:")); + } + num_found++; - date_activity[0] = '\0'; - date_tmp = localtime (&(ptr_client->last_activity)); - if (date_tmp) - { - strftime (date_activity, sizeof (date_activity), - "%a, %d %b %Y %H:%M:%S", date_tmp); - } + date_start[0] = '\0'; + date_tmp = localtime (&(ptr_client->start_time)); + if (date_tmp) + { + strftime (date_start, sizeof (date_start), + "%a, %d %b %Y %H:%M:%S", date_tmp); + } - if (full) - { - weechat_printf (NULL, - _(" id: %d, %s%s%s (%s%s%s), " - "started on: %s, last activity: %s, " - "bytes: %lu recv, %lu sent"), - ptr_client->id, - RELAY_COLOR_CHAT_HOST, - ptr_client->address, - RELAY_COLOR_CHAT, - RELAY_COLOR_CHAT_BUFFER, - relay_client_status_string[ptr_client->status], - RELAY_COLOR_CHAT, - date_start, - date_activity, - ptr_client->bytes_recv, - ptr_client->bytes_sent); - } - else - { - if (!RELAY_CLIENT_HAS_ENDED(ptr_client)) - { - weechat_printf (NULL, - _(" id: %d, %s%s%s, started on: %s"), - ptr_client->id, - RELAY_COLOR_CHAT_HOST, - ptr_client->address, - RELAY_COLOR_CHAT, - date_start); - } - } - i++; + date_activity[0] = '\0'; + date_tmp = localtime (&(ptr_client->last_activity)); + if (date_tmp) + { + strftime (date_activity, sizeof (date_activity), + "%a, %d %b %Y %H:%M:%S", date_tmp); + } + + if (full) + { + weechat_printf (NULL, + _(" %s%s%s (%s%s%s), started on: %s, last activity: %s, " + "bytes: %lu recv, %lu sent"), + RELAY_COLOR_CHAT_CLIENT, + ptr_client->desc, + RELAY_COLOR_CHAT, + weechat_color (weechat_config_string (relay_config_color_status[ptr_client->status])), + relay_client_status_string[ptr_client->status], + RELAY_COLOR_CHAT, + date_start, + date_activity, + ptr_client->bytes_recv, + ptr_client->bytes_sent); + } + else + { + weechat_printf (NULL, + _(" %s%s%s (%s%s%s), started on: %s"), + RELAY_COLOR_CHAT_CLIENT, + ptr_client->desc, + RELAY_COLOR_CHAT, + weechat_color (weechat_config_string (relay_config_color_status[ptr_client->status])), + relay_client_status_string[ptr_client->status], + RELAY_COLOR_CHAT, + date_start); } } - else - weechat_printf (NULL, _("No client for relay")); + + if (num_found == 0) + { + weechat_printf (NULL, + (full) ? + _("No client for relay") : + _("No connected client for relay")); + } } /* @@ -259,6 +270,11 @@ relay_command_relay (void *data, struct t_gui_buffer *buffer, int argc, relay_raw_open (1); return WEECHAT_RC_OK; } + if (weechat_strcasecmp (argv[1], "sslcertkey") == 0) + { + relay_network_set_ssl_cert_key (1); + return WEECHAT_RC_OK; + } } if (!relay_buffer) @@ -300,7 +316,8 @@ relay_command_init () N_("list|listfull|listrelay" " || add <protocol.name> <port>" " || del <protocol.name>" - " || raw"), + " || raw" + " || sslcertkey"), N_(" list: list relay clients (only active " "relays)\n" " listfull: list relay clients (verbose, all " @@ -313,20 +330,29 @@ relay_command_init () "server to share\n" " - protocol \"weechat\" (name is " "not used)\n" + " Note: the protocol can be prefixed " + "by \"ssl.\" to enable SSL\n" " port: port used for relay\n" - " raw: open buffer with raw Relay data\n\n" + " raw: open buffer with raw Relay data\n" + " sslcertkey: set SSL certificate/key using path " + "in option relay.network.ssl_cert_key\n\n" "Without argument, this command opens buffer " "with list of relay clients.\n\n" "Examples:\n" " irc proxy, for server \"freenode\":\n" " /relay add irc.freenode 8000\n" + " irc proxy, for server \"freenode\", with SSL:\n" + " /relay add ssl.irc.freenode 8001\n" " weechat protocol:\n" - " /relay add weechat 8001"), + " /relay add weechat 9000\n" + " weechat protocol with SSL:\n" + " /relay add ssl.weechat 9001"), "list %(relay_relays)" " || listfull %(relay_relays)" " || listrelay" " || add %(relay_protocol_name) %(relay_free_port)" " || del %(relay_relays)" - " || raw", + " || raw" + " || sslcertkey", &relay_command_relay, NULL); } diff --git a/src/plugins/relay/relay-completion.c b/src/plugins/relay/relay-completion.c index dc14c9ca6..9698de5f5 100644 --- a/src/plugins/relay/relay-completion.c +++ b/src/plugins/relay/relay-completion.c @@ -41,7 +41,7 @@ relay_completion_protocol_name_cb (void *data, const char *completion_item, struct t_gui_completion *completion) { struct t_infolist *infolist; - char protocol_name[256]; + char protocol_name[512]; /* make C compiler happy */ (void) data; @@ -57,12 +57,18 @@ relay_completion_protocol_name_cb (void *data, const char *completion_item, weechat_infolist_string (infolist, "name")); weechat_hook_completion_list_add (completion, protocol_name, 0, WEECHAT_LIST_POS_SORT); + snprintf (protocol_name, sizeof (protocol_name), "ssl.irc.%s", + weechat_infolist_string (infolist, "name")); + weechat_hook_completion_list_add (completion, protocol_name, + 0, WEECHAT_LIST_POS_SORT); } weechat_infolist_free (infolist); } weechat_hook_completion_list_add (completion, "weechat", 0, WEECHAT_LIST_POS_SORT); + weechat_hook_completion_list_add (completion, "ssl.weechat", + 0, WEECHAT_LIST_POS_SORT); return WEECHAT_RC_OK; } @@ -78,7 +84,7 @@ relay_completion_relays_cb (void *data, const char *completion_item, struct t_gui_completion *completion) { struct t_relay_server *ptr_server; - char protocol_name[256]; + char protocol_name[512]; /* make C compiler happy */ (void) data; @@ -88,7 +94,8 @@ relay_completion_relays_cb (void *data, const char *completion_item, for (ptr_server = relay_servers; ptr_server; ptr_server = ptr_server->next_server) { - snprintf (protocol_name, sizeof (protocol_name), "%s%s%s", + snprintf (protocol_name, sizeof (protocol_name), "%s%s%s%s", + (ptr_server->ssl) ? "ssl." : "", relay_protocol_string[ptr_server->protocol], (ptr_server->protocol_args) ? "." : "", (ptr_server->protocol_args) ? ptr_server->protocol_args : ""); diff --git a/src/plugins/relay/relay-config.c b/src/plugins/relay/relay-config.c index 0080f0cff..5b6aaa862 100644 --- a/src/plugins/relay/relay-config.c +++ b/src/plugins/relay/relay-config.c @@ -30,6 +30,7 @@ #include "relay-config.h" #include "relay-client.h" #include "relay-buffer.h" +#include "relay-network.h" #include "relay-server.h" @@ -43,6 +44,7 @@ struct t_config_option *relay_config_look_raw_messages; /* relay config, color section */ +struct t_config_option *relay_config_color_client; struct t_config_option *relay_config_color_text; struct t_config_option *relay_config_color_text_bg; struct t_config_option *relay_config_color_text_selected; @@ -55,6 +57,7 @@ struct t_config_option *relay_config_network_bind_address; struct t_config_option *relay_config_network_compression_level; struct t_config_option *relay_config_network_max_clients; struct t_config_option *relay_config_network_password; +struct t_config_option *relay_config_network_ssl_cert_key; /* other */ @@ -139,6 +142,22 @@ relay_config_change_network_bind_address_cb (void *data, } /* + * relay_config_change_network_ssl_cert_key: called when ssl_cert_key is changed + */ + +void +relay_config_change_network_ssl_cert_key (void *data, + struct t_config_option *option) +{ + /* make C compiler happy */ + (void) data; + (void) option; + + if (relay_network_init_ok) + relay_network_set_ssl_cert_key (1); +} + +/* * relay_config_change_port_cb: callback called when relay port option is * modified */ @@ -219,7 +238,7 @@ relay_config_create_option_port (void *data, const char *option_name, const char *value) { - int rc, protocol_number; + int rc, protocol_number, ssl; char *error, *protocol, *protocol_args; long port; struct t_relay_server *ptr_server; @@ -229,38 +248,52 @@ relay_config_create_option_port (void *data, rc = WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; - relay_server_get_protocol_args (option_name, - &protocol, &protocol_args); - protocol_number = -1; port = -1; - if (protocol) - protocol_number = relay_protocol_search (protocol); + relay_server_get_protocol_args (option_name, + &ssl, &protocol, &protocol_args); - if (protocol_number < 0) +#ifndef HAVE_GNUTLS + if (ssl) { - weechat_printf (NULL, _("%s%s: error: unknown protocol \"%s\""), - weechat_prefix ("error"), - RELAY_PLUGIN_NAME, protocol); + weechat_printf (NULL, + _("%s%s: cannot use SSL because WeeChat was not built " + "with GnuTLS support"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME); rc = WEECHAT_CONFIG_OPTION_SET_ERROR; } +#endif - if ((protocol_number == RELAY_PROTOCOL_WEECHAT) && protocol_args) - { - weechat_printf (NULL, _("%s%s: error: name is not allowed for protocol " - "\"%s\""), - weechat_prefix ("error"), - RELAY_PLUGIN_NAME, protocol); - rc = WEECHAT_CONFIG_OPTION_SET_ERROR; - } - else if ((protocol_number == RELAY_PROTOCOL_IRC) && !protocol_args) + if (rc != WEECHAT_CONFIG_OPTION_SET_ERROR) { - weechat_printf (NULL, _("%s%s: error: name is not required for protocol " - "\"%s\""), - weechat_prefix ("error"), - RELAY_PLUGIN_NAME, protocol); - rc = WEECHAT_CONFIG_OPTION_SET_ERROR; + if (protocol) + protocol_number = relay_protocol_search (protocol); + + if (protocol_number < 0) + { + weechat_printf (NULL, _("%s%s: error: unknown protocol \"%s\""), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, protocol); + rc = WEECHAT_CONFIG_OPTION_SET_ERROR; + } + + if ((protocol_number == RELAY_PROTOCOL_WEECHAT) && protocol_args) + { + weechat_printf (NULL, _("%s%s: error: name is not allowed for " + "protocol \"%s\""), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, protocol); + rc = WEECHAT_CONFIG_OPTION_SET_ERROR; + } + else if ((protocol_number == RELAY_PROTOCOL_IRC) && !protocol_args) + { + weechat_printf (NULL, _("%s%s: error: name is not required for " + "protocol \"%s\""), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, protocol); + rc = WEECHAT_CONFIG_OPTION_SET_ERROR; + } } if (rc != WEECHAT_CONFIG_OPTION_SET_ERROR) @@ -290,7 +323,7 @@ relay_config_create_option_port (void *data, if (rc != WEECHAT_CONFIG_OPTION_SET_ERROR) { - if (relay_server_new (protocol_number, protocol_args, port)) + if (relay_server_new (protocol_number, protocol_args, port, ssl)) { /* create config option */ weechat_config_new_option ( @@ -376,22 +409,28 @@ relay_config_init () return 0; } + relay_config_color_client = weechat_config_new_option ( + relay_config_file, ptr_section, + "client", "color", + N_("text color for client description"), + NULL, 0, 0, "cyan", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); relay_config_color_text = weechat_config_new_option ( relay_config_file, ptr_section, "text", "color", - N_("text color"), + N_("text color in relay buffer"), NULL, 0, 0, "default", NULL, 0, NULL, NULL, &relay_config_refresh_cb, NULL, NULL, NULL); relay_config_color_text_bg = weechat_config_new_option ( relay_config_file, ptr_section, "text_bg", "color", - N_("background color"), + N_("background color in relay buffer"), NULL, 0, 0, "default", NULL, 0, NULL, NULL, &relay_config_refresh_cb, NULL, NULL, NULL); relay_config_color_text_selected = weechat_config_new_option ( relay_config_file, ptr_section, "text_selected", "color", - N_("text color of selected client line"), + N_("text color of selected line in relay buffer"), NULL, 0, 0, "white", NULL, 0, NULL, NULL, &relay_config_refresh_cb, NULL, NULL, NULL); relay_config_color_status[RELAY_STATUS_CONNECTING] = weechat_config_new_option ( @@ -472,6 +511,13 @@ relay_config_init () N_("password required by clients to access this relay (empty value " "means no password required)"), NULL, 0, 0, "", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + relay_config_network_ssl_cert_key = weechat_config_new_option ( + relay_config_file, ptr_section, + "ssl_cert_key", "string", + N_("file with SSL certificate and private key (for serving clients " + "with SSL)"), + NULL, 0, 0, "%h/ssl/relay.pem", NULL, 0, NULL, NULL, + &relay_config_change_network_ssl_cert_key, NULL, NULL, NULL); ptr_section = weechat_config_new_section (relay_config_file, "port", 1, 1, diff --git a/src/plugins/relay/relay-config.h b/src/plugins/relay/relay-config.h index ef9056e10..0576b36e9 100644 --- a/src/plugins/relay/relay-config.h +++ b/src/plugins/relay/relay-config.h @@ -30,15 +30,18 @@ extern struct t_config_section *relay_config_section_port; extern struct t_config_option *relay_config_look_auto_open_buffer; extern struct t_config_option *relay_config_look_raw_messages; +extern struct t_config_option *relay_config_color_client; extern struct t_config_option *relay_config_color_text; extern struct t_config_option *relay_config_color_text_bg; extern struct t_config_option *relay_config_color_text_selected; extern struct t_config_option *relay_config_color_status[]; +extern struct t_config_option *relay_config_network_allowed_ips; extern struct t_config_option *relay_config_network_bind_address; +extern struct t_config_option *relay_config_network_compression_level; extern struct t_config_option *relay_config_network_max_clients; extern struct t_config_option *relay_config_network_password; -extern struct t_config_option *relay_config_network_compression_level; +extern struct t_config_option *relay_config_network_ssl_cert_key; extern regex_t *relay_config_regex_allowed_ips; diff --git a/src/plugins/relay/relay-network.c b/src/plugins/relay/relay-network.c new file mode 100644 index 000000000..054ea4969 --- /dev/null +++ b/src/plugins/relay/relay-network.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat 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 3 of the License, or + * (at your option) any later version. + * + * WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * relay-network.c: network functions for relay plugin + */ + +#include <stdlib.h> + +#ifdef HAVE_GNUTLS +#include <gnutls/gnutls.h> +#endif + +#include "../weechat-plugin.h" +#include "relay.h" +#include "relay-network.h" +#include "relay-config.h" + + +int relay_network_init_ok = 0; +int relay_network_init_ssl_cert_key_ok = 0; + +#ifdef HAVE_GNUTLS +gnutls_certificate_credentials_t relay_gnutls_x509_cred; +gnutls_priority_t *relay_gnutls_priority_cache; +gnutls_dh_params_t relay_gnutls_dh_params; +#endif + + +/* + * relay_network_set_ssl_cert_key: set SSL certificate/key file + * if verbose == 1, a message is displayed if + * successful, otherwise a warning (if no + * cert/key found in file) + */ + +void +relay_network_set_ssl_cert_key (int verbose) +{ + int ret; + +#ifdef HAVE_GNUTLS + char *certkey_path, *certkey_path2; + + gnutls_certificate_free_credentials (relay_gnutls_x509_cred); + gnutls_certificate_allocate_credentials (&relay_gnutls_x509_cred); + + relay_network_init_ssl_cert_key_ok = 0; + + certkey_path = weechat_string_expand_home (weechat_config_string (relay_config_network_ssl_cert_key)); + if (certkey_path) + { + certkey_path2 = weechat_string_replace (certkey_path, "%h", + weechat_info_get ("weechat_dir", + NULL)); + if (certkey_path2) + { + ret = gnutls_certificate_set_x509_key_file (relay_gnutls_x509_cred, + certkey_path2, + certkey_path2, + GNUTLS_X509_FMT_PEM); + if (ret >= 0) + { + relay_network_init_ssl_cert_key_ok = 1; + if (verbose) + { + weechat_printf (NULL, + _("%s: SSL certificate and key have been " + "set"), + RELAY_PLUGIN_NAME); + } + } + else + { + if (verbose) + { + weechat_printf (NULL, + _("%s%s: warning: no SSL certificate/key " + "found (option relay.network.ssl_cert_key)"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME); + } + } + free (certkey_path2); + } + free (certkey_path); + } +#endif +} + +/* + * relay_network_init: init network for relay + */ + +void +relay_network_init () +{ +#ifdef HAVE_GNUTLS + int bits; + + /* credentials */ + gnutls_certificate_allocate_credentials (&relay_gnutls_x509_cred); + relay_network_set_ssl_cert_key (0); + + /* Diffie-Hellman parameters */ + bits = gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH, GNUTLS_SEC_PARAM_LOW); + gnutls_dh_params_init (&relay_gnutls_dh_params); + gnutls_dh_params_generate2 (relay_gnutls_dh_params, bits); + gnutls_certificate_set_dh_params (relay_gnutls_x509_cred, relay_gnutls_dh_params); + + /* priority */ + relay_gnutls_priority_cache = malloc (sizeof (*relay_gnutls_priority_cache)); + if (relay_gnutls_priority_cache) + { + if (gnutls_priority_init (relay_gnutls_priority_cache, + "PERFORMANCE", NULL) != GNUTLS_E_SUCCESS) + { + weechat_printf (NULL, + _("%s%s: unable to initialize priority for SSL"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME); + free (relay_gnutls_priority_cache); + relay_gnutls_priority_cache = NULL; + } + } +#endif + relay_network_init_ok = 1; +} + +/* + * relay_network_end: end network for relay + */ + +void +relay_network_end () +{ + if (relay_network_init_ok) + { +#ifdef HAVE_GNUTLS + if (relay_gnutls_priority_cache) + { + gnutls_priority_deinit (*relay_gnutls_priority_cache); + free (relay_gnutls_priority_cache); + } + gnutls_certificate_free_credentials (relay_gnutls_x509_cred); +#endif + relay_network_init_ok = 0; + } +} diff --git a/src/plugins/relay/relay-network.h b/src/plugins/relay/relay-network.h new file mode 100644 index 000000000..8db57eed3 --- /dev/null +++ b/src/plugins/relay/relay-network.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat 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 3 of the License, or + * (at your option) any later version. + * + * WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_RELAY_NETWORK_H +#define __WEECHAT_RELAY_NETWORK_H 1 + +#ifdef HAVE_GNUTLS +#include <gnutls/gnutls.h> +#endif + +extern int relay_network_init_ok; +extern int relay_network_init_ssl_cert_key_ok; + +#ifdef HAVE_GNUTLS +extern gnutls_certificate_credentials_t relay_gnutls_x509_cred; +extern gnutls_priority_t *relay_gnutls_priority_cache; +#endif + +extern void relay_network_set_ssl_cert_key (int verbose); +extern void relay_network_init (); +extern void relay_network_end (); + +#endif /* __WEECHAT_RELAY_NETWORK_H */ diff --git a/src/plugins/relay/relay-server.c b/src/plugins/relay/relay-server.c index fa0844fdb..cf1bc3694 100644 --- a/src/plugins/relay/relay-server.c +++ b/src/plugins/relay/relay-server.c @@ -53,10 +53,16 @@ struct t_relay_server *last_relay_server = NULL; void relay_server_get_protocol_args (const char *protocol_and_args, - char **protocol, char **protocol_args) + int *ssl, char **protocol, char **protocol_args) { char *pos; + *ssl = 0; + if (strncmp (protocol_and_args, "ssl.", 4) == 0) + { + *ssl = 1; + protocol_and_args += 4; + } pos = strchr (protocol_and_args, '.'); if (pos) { @@ -78,11 +84,12 @@ relay_server_get_protocol_args (const char *protocol_and_args, struct t_relay_server * relay_server_search (const char *protocol_and_args) { + int ssl; char *protocol, *protocol_args; struct t_relay_server *ptr_server; relay_server_get_protocol_args (protocol_and_args, - &protocol, &protocol_args); + &ssl, &protocol, &protocol_args); ptr_server = NULL; @@ -91,7 +98,8 @@ relay_server_search (const char *protocol_and_args) for (ptr_server = relay_servers; ptr_server; ptr_server = ptr_server->next_server) { - if (strcmp (protocol, relay_protocol_string[ptr_server->protocol]) == 0) + if ((ptr_server->ssl == ssl) + && (strcmp (protocol, relay_protocol_string[ptr_server->protocol]) == 0)) { if (!protocol_args && !ptr_server->protocol_args) break; @@ -172,7 +180,7 @@ relay_server_sock_cb (void *data, int fd) struct t_relay_server *server; struct sockaddr_in client_addr; socklen_t client_length; - int client_fd, flags; + int client_fd, flags, set; char ipv4_address[INET_ADDRSTRLEN + 1], *ptr_address; /* make C compiler happy */ @@ -229,6 +237,19 @@ relay_server_sock_cb (void *data, int fd) flags = 0; fcntl (client_fd, F_SETFL, flags | O_NONBLOCK); + /* set socket option SO_REUSEADDR */ + set = 1; + if (setsockopt (client_fd, SOL_SOCKET, SO_REUSEADDR, + (void *) &set, sizeof (set)) < 0) + { + weechat_printf (NULL, + _("%s%s: cannot set socket option " + "\"SO_REUSEADDR\""), + weechat_prefix ("error"), RELAY_PLUGIN_NAME); + close (client_fd); + return WEECHAT_RC_OK; + } + /* add the client */ relay_client_new (client_fd, ptr_address, server); @@ -313,12 +334,13 @@ relay_server_create_socket (struct t_relay_server *server) listen (server->sock, max_clients); weechat_printf (NULL, - _("%s: listening on port %d (relay: %s%s%s, max %d clients)"), + _("%s: listening on port %d (relay: %s%s%s,%s max %d clients)"), RELAY_PLUGIN_NAME, server->port, relay_protocol_string[server->protocol], (server->protocol_args) ? "." : "", (server->protocol_args) ? server->protocol_args : "", + (server->ssl) ? " SSL," : "", max_clients); server->hook_fd = weechat_hook_fd (server->sock, @@ -338,7 +360,7 @@ relay_server_create_socket (struct t_relay_server *server) struct t_relay_server * relay_server_new (enum t_relay_protocol protocol, const char *protocol_args, - int port) + int port, int ssl) { struct t_relay_server *new_server; @@ -357,6 +379,7 @@ relay_server_new (enum t_relay_protocol protocol, new_server->protocol_args = (protocol_args) ? strdup (protocol_args) : NULL; new_server->port = port; + new_server->ssl = ssl; new_server->sock = -1; new_server->hook_fd = NULL; new_server->start_time = 0; @@ -469,6 +492,7 @@ relay_server_print_log () relay_protocol_string[ptr_server->protocol]); weechat_log_printf (" protocol_args . . . : '%s'", ptr_server->protocol_args); weechat_log_printf (" port. . . . . . . . : %d", ptr_server->port); + weechat_log_printf (" ssl . . . . . . . . : %d", ptr_server->ssl); weechat_log_printf (" sock. . . . . . . . : %d", ptr_server->sock); weechat_log_printf (" hook_fd . . . . . . : 0x%lx", ptr_server->hook_fd); weechat_log_printf (" start_time. . . . . : %ld", ptr_server->start_time); diff --git a/src/plugins/relay/relay-server.h b/src/plugins/relay/relay-server.h index 2bd7e1420..300671043 100644 --- a/src/plugins/relay/relay-server.h +++ b/src/plugins/relay/relay-server.h @@ -20,12 +20,17 @@ #ifndef __WEECHAT_RELAY_SERVER_H #define __WEECHAT_RELAY_SERVER_H 1 +#ifdef HAVE_GNUTLS +#define RELAY_SERVER_GNUTLS_DH_BITS 1024 +#endif + struct t_relay_server { enum t_relay_protocol protocol; /* protocol (irc,..) */ char *protocol_args; /* arguments used for protocol */ /* example: server for irc protocol */ int port; /* listening on this port */ + int ssl; /* 1 if SSL is enabled */ int sock; /* socket for connection */ struct t_hook *hook_fd; /* hook for socket */ time_t start_time; /* start time */ @@ -37,6 +42,7 @@ extern struct t_relay_server *relay_servers; extern struct t_relay_server *last_relay_server; extern void relay_server_get_protocol_args (const char *protocol_and_string, + int *ssl, char **protocol, char **protocol_args); extern struct t_relay_server *relay_server_search (const char *protocol_and_args); @@ -45,7 +51,7 @@ extern void relay_server_close_socket (struct t_relay_server *server); extern int relay_server_create_socket (struct t_relay_server *server); extern struct t_relay_server *relay_server_new (enum t_relay_protocol protocol, const char *protocol_args, - int port); + int port, int ssl); extern void relay_server_update_port (struct t_relay_server *server, int port); extern void relay_server_free (struct t_relay_server *server); extern void relay_server_free_all (); diff --git a/src/plugins/relay/relay.c b/src/plugins/relay/relay.c index 92b010dd3..5e392e31f 100644 --- a/src/plugins/relay/relay.c +++ b/src/plugins/relay/relay.c @@ -31,6 +31,7 @@ #include "relay-completion.h" #include "relay-config.h" #include "relay-info.h" +#include "relay-network.h" #include "relay-raw.h" #include "relay-server.h" #include "relay-upgrade.h" @@ -81,6 +82,8 @@ relay_signal_upgrade_cb (void *data, const char *signal, const char *type_data, void *signal_data) { struct t_relay_server *ptr_server; + struct t_relay_client *ptr_client; + int disconnected; /* make C compiler happy */ (void) data; @@ -90,12 +93,47 @@ relay_signal_upgrade_cb (void *data, const char *signal, const char *type_data, relay_signal_upgrade_received = 1; + /* close socket for relay servers */ for (ptr_server = relay_servers; ptr_server; ptr_server = ptr_server->next_server) { relay_server_close_socket (ptr_server); } + /* + * FIXME: it's not possible to upgrade with SSL clients connected (GnuTLS + * lib can't reload data after upgrade), so we close connection for + * all SSL clients currently connected + */ + disconnected = 0; + for (ptr_client = relay_clients; ptr_client; + ptr_client = ptr_client->next_client) + { + if ((ptr_client->sock >= 0) && ptr_client->ssl) + { + disconnected++; + weechat_printf (NULL, + _("%s%s: disconnecting from client %s%s%s because " + "upgrade can't work for clients connected via SSL"), + weechat_prefix ("error"), + RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_CLIENT, + ptr_client->desc, + RELAY_COLOR_CHAT); + relay_client_set_status (ptr_client, RELAY_STATUS_DISCONNECTED); + } + } + if (disconnected > 0) + { + weechat_printf (NULL, + /* TRANSLATORS: "%s" after "%d" is "client" or "clients" */ + _("%s%s: disconnected from %d %s (SSL connection " + "not supported with upgrade)"), + weechat_prefix ("error"), RELAY_PLUGIN_NAME, + disconnected, + NG_("client", "clients", disconnected)); + } + return WEECHAT_RC_OK; } @@ -151,6 +189,8 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) if (relay_config_read () < 0) return WEECHAT_RC_ERROR; + relay_network_init (); + relay_command_init (); /* hook completions */ @@ -211,5 +251,7 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) relay_client_free_all (); } + relay_network_end (); + return WEECHAT_RC_OK; } diff --git a/src/plugins/relay/relay.h b/src/plugins/relay/relay.h index b2ab5023c..a6047a6b4 100644 --- a/src/plugins/relay/relay.h +++ b/src/plugins/relay/relay.h @@ -40,6 +40,7 @@ enum t_relay_protocol #define RELAY_COLOR_CHAT weechat_color("chat") #define RELAY_COLOR_CHAT_HOST weechat_color("chat_host") #define RELAY_COLOR_CHAT_BUFFER weechat_color("chat_buffer") +#define RELAY_COLOR_CHAT_CLIENT weechat_color(weechat_config_string(relay_config_color_client)) extern char *relay_protocol_string[]; diff --git a/src/plugins/relay/weechat/relay-weechat-protocol.c b/src/plugins/relay/weechat/relay-weechat-protocol.c index 1ae66aee4..464974dc7 100644 --- a/src/plugins/relay/weechat/relay-weechat-protocol.c +++ b/src/plugins/relay/weechat/relay-weechat-protocol.c @@ -918,8 +918,12 @@ relay_weechat_protocol_recv (struct t_relay_client *client, char *data) /* display debug message */ if (weechat_relay_plugin->debug >= 2) { - weechat_printf (NULL, "%s: recv from client %d: \"%s\"", - RELAY_PLUGIN_NAME, client->id, data); + weechat_printf (NULL, "%s: recv from client %s%s%s: \"%s\"", + RELAY_PLUGIN_NAME, + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT, + data); } /* display message in raw buffer */ @@ -996,9 +1000,13 @@ relay_weechat_protocol_recv (struct t_relay_client *client, char *data) { weechat_printf (NULL, _("%s%s: failed to execute command \"%s\" " - "for client %d"), + "for client %s%s%s"), weechat_prefix ("error"), - RELAY_PLUGIN_NAME, command, client->id); + RELAY_PLUGIN_NAME, + command, + RELAY_COLOR_CHAT_CLIENT, + client->desc, + RELAY_COLOR_CHAT); } } break; diff --git a/src/plugins/relay/weechat/relay-weechat-protocol.h b/src/plugins/relay/weechat/relay-weechat-protocol.h index a0e555b85..7f25288ab 100644 --- a/src/plugins/relay/weechat/relay-weechat-protocol.h +++ b/src/plugins/relay/weechat/relay-weechat-protocol.h @@ -44,12 +44,17 @@ { \ weechat_printf (NULL, \ _("%s%s: too few arguments received from " \ - "client %d for command \"%s\" " \ + "client %s%s%s for command \"%s\" " \ "(received: %d arguments, expected: at " \ "least %d)"), \ weechat_prefix ("error"), \ RELAY_PLUGIN_NAME, \ - client->id, command, argc, __min_args); \ + RELAY_COLOR_CHAT_CLIENT, \ + client->desc, \ + RELAY_COLOR_CHAT, \ + command, \ + argc, \ + __min_args); \ } \ return WEECHAT_RC_ERROR; \ } |