1
0
mirror of https://github.com/weechat/weechat.git synced 2026-07-01 07:16:37 +02:00

relay: add connection to remote (issue #2066)

Connection to remote:

- handshake: offer support for all supported hash algorithms
- network connect with a socket
- upgrade to websocket and authenticate with remote (password/TOTP)
- check websocket response
- get list of buffers (not used yet)

Note: connection to remote with TLS or a proxy is not yet supported.
This commit is contained in:
Sébastien Helleu
2024-03-31 09:49:10 +02:00
parent fd32192464
commit 90b855e1aa
25 changed files with 2667 additions and 999 deletions
+2
View File
@@ -49,6 +49,8 @@ if(ENABLE_CJSON)
api/relay-api.c api/relay-api.h
api/relay-api-msg.c api/relay-api-msg.h
api/relay-api-protocol.c api/relay-api-protocol.h
# API relay remote
api/remote/relay-remote-network.c api/remote/relay-remote-network.h
)
endif()
+1 -1
View File
@@ -172,7 +172,7 @@ relay_api_msg_send_json_internal (struct t_relay_client *client,
string = cJSON_PrintUnformatted (json);
num_bytes = relay_client_send (
client,
RELAY_CLIENT_MSG_STANDARD,
RELAY_MSG_STANDARD,
string,
(string) ? strlen (string) : 0,
NULL); /* raw_message */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2024 Sébastien 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 <https://www.gnu.org/licenses/>.
*/
#ifndef WEECHAT_PLUGIN_RELAY_REMOTE_NETWORK_H
#define WEECHAT_PLUGIN_RELAY_REMOTE_NETWORK_H
extern int relay_remote_network_connect (struct t_relay_remote *remote);
extern void relay_remote_network_disconnect (struct t_relay_remote *remote);
#endif /* WEECHAT_PLUGIN_RELAY_REMOTE_NETWORK_H */
+1 -1
View File
@@ -279,7 +279,7 @@ relay_irc_sendf (struct t_relay_client *client, const char *format, ...)
if (message)
{
snprintf (message, length, "%s\r\n", ptr_msg2);
relay_client_send (client, RELAY_CLIENT_MSG_STANDARD,
relay_client_send (client, RELAY_MSG_STANDARD,
message, strlen (message), NULL);
free (message);
}
+53 -52
View File
@@ -52,9 +52,6 @@
char *relay_client_data_type_string[] = /* strings for data types */
{ "text", "binary", "http" };
char *relay_client_msg_type_string[] = /* prefix in raw buffer for message */
{ "", "[PING]\n", "[PONG]\n", "[CLOSE]\n" };
struct t_relay_client *relay_clients = NULL;
struct t_relay_client *last_relay_client = NULL;
int relay_client_count = 0; /* number of clients */
@@ -313,9 +310,9 @@ relay_client_recv_text_single_line (struct t_relay_client *client)
pos - client->partial_message + 1);
if (raw_msg)
{
relay_raw_print (client, RELAY_CLIENT_MSG_STANDARD,
RELAY_RAW_FLAG_RECV,
raw_msg, strlen (raw_msg) + 1);
relay_raw_print_client (client, RELAY_MSG_STANDARD,
RELAY_RAW_FLAG_RECV,
raw_msg, strlen (raw_msg) + 1);
free (raw_msg);
}
@@ -380,10 +377,10 @@ relay_client_recv_text_multi_line (struct t_relay_client *client)
return;
/* print message in raw buffer */
relay_raw_print (client, RELAY_CLIENT_MSG_STANDARD,
RELAY_RAW_FLAG_RECV,
client->partial_message,
strlen (client->partial_message) + 1);
relay_raw_print_client (client, RELAY_MSG_STANDARD,
RELAY_RAW_FLAG_RECV,
client->partial_message,
strlen (client->partial_message) + 1);
/*
* interpret text from client, according to the relay
@@ -457,7 +454,7 @@ relay_client_recv_text_buffer (struct t_relay_client *client,
index = 0;
while (index < length_buffer)
{
msg_type = RELAY_CLIENT_MSG_STANDARD;
msg_type = RELAY_MSG_STANDARD;
/*
* in case of websocket, we can receive PING from client:
@@ -466,30 +463,30 @@ relay_client_recv_text_buffer (struct t_relay_client *client,
if (client->websocket == RELAY_CLIENT_WEBSOCKET_READY)
{
msg_type = (unsigned char)buffer[index];
if (msg_type == RELAY_CLIENT_MSG_PING)
if (msg_type == RELAY_MSG_PING)
{
/* print message in raw buffer */
relay_raw_print (client, RELAY_CLIENT_MSG_PING,
RELAY_RAW_FLAG_RECV | RELAY_RAW_FLAG_BINARY,
buffer + index + 1,
strlen (buffer + index + 1));
relay_raw_print_client (client, RELAY_MSG_PING,
RELAY_RAW_FLAG_RECV | RELAY_RAW_FLAG_BINARY,
buffer + index + 1,
strlen (buffer + index + 1));
/* answer with a PONG */
relay_client_send (client,
RELAY_CLIENT_MSG_PONG,
RELAY_MSG_PONG,
buffer + index + 1,
strlen (buffer + index + 1),
NULL);
}
else if (msg_type == RELAY_CLIENT_MSG_CLOSE)
else if (msg_type == RELAY_MSG_CLOSE)
{
/* print message in raw buffer */
relay_raw_print (client, RELAY_CLIENT_MSG_CLOSE,
RELAY_RAW_FLAG_RECV | RELAY_RAW_FLAG_BINARY,
buffer + index + 1,
strlen (buffer + index + 1));
relay_raw_print_client (client, RELAY_MSG_CLOSE,
RELAY_RAW_FLAG_RECV | RELAY_RAW_FLAG_BINARY,
buffer + index + 1,
strlen (buffer + index + 1));
/* answer with a CLOSE */
relay_client_send (client,
RELAY_CLIENT_MSG_CLOSE,
RELAY_MSG_CLOSE,
buffer + index + 1,
strlen (buffer + index + 1),
NULL);
@@ -501,7 +498,7 @@ relay_client_recv_text_buffer (struct t_relay_client *client,
index++;
}
if (msg_type == RELAY_CLIENT_MSG_STANDARD)
if (msg_type == RELAY_MSG_STANDARD)
{
if ((client->websocket == RELAY_CLIENT_WEBSOCKET_INITIALIZING)
|| (client->recv_data_type == RELAY_CLIENT_DATA_HTTP))
@@ -549,28 +546,28 @@ relay_client_read_websocket_frames (struct t_relay_client *client,
}
switch (frames[i].opcode)
{
case RELAY_CLIENT_MSG_PING:
case RELAY_MSG_PING:
/* print message in raw buffer */
relay_raw_print (client, RELAY_CLIENT_MSG_PING,
RELAY_RAW_FLAG_RECV | RELAY_RAW_FLAG_BINARY,
frames[i].payload,
frames[i].payload_size);
relay_raw_print_client (client, RELAY_MSG_PING,
RELAY_RAW_FLAG_RECV | RELAY_RAW_FLAG_BINARY,
frames[i].payload,
frames[i].payload_size);
/* answer with a PONG */
relay_client_send (client,
RELAY_CLIENT_MSG_PONG,
RELAY_MSG_PONG,
frames[i].payload,
frames[i].payload_size,
NULL);
break;
case RELAY_CLIENT_MSG_CLOSE:
case RELAY_MSG_CLOSE:
/* print message in raw buffer */
relay_raw_print (client, RELAY_CLIENT_MSG_CLOSE,
RELAY_RAW_FLAG_RECV | RELAY_RAW_FLAG_BINARY,
frames[i].payload,
frames[i].payload_size);
relay_raw_print_client (client, RELAY_MSG_CLOSE,
RELAY_RAW_FLAG_RECV | RELAY_RAW_FLAG_BINARY,
frames[i].payload,
frames[i].payload_size);
/* answer with a CLOSE */
relay_client_send (client,
RELAY_CLIENT_MSG_CLOSE,
RELAY_MSG_CLOSE,
frames[i].payload,
frames[i].payload_size,
NULL);
@@ -653,11 +650,14 @@ relay_client_recv_buffer (struct t_relay_client *client,
frames = NULL;
num_frames = 0;
rc = relay_websocket_decode_frame (
client,
(buffer2) ? (unsigned char *)buffer2 : (unsigned char *)buffer,
(buffer2) ? (unsigned long long)buffer2_size : (unsigned long long)buffer_size,
1, /* expect_masked_frame */
client->ws_deflate,
&frames,
&num_frames);
&num_frames,
&client->partial_ws_frame,
&client->partial_ws_frame_size);
if (buffer2)
free (buffer2);
if (!rc)
@@ -899,7 +899,7 @@ relay_client_send_outqueue (struct t_relay_client *client)
* (so that it is displayed only one time, even if
* message is sent in many chunks)
*/
relay_raw_print (
relay_raw_print_client (
client,
client->outqueue->raw_msg_type[i],
client->outqueue->raw_flags[i],
@@ -1033,7 +1033,7 @@ relay_client_timer_send_cb (const void *pointer, void *data,
void
relay_client_outqueue_add (struct t_relay_client *client,
const char *data, int data_size,
enum t_relay_client_msg_type raw_msg_type[2],
enum t_relay_msg_type raw_msg_type[2],
int raw_flags[2],
const char *raw_message[2],
int raw_size[2])
@@ -1059,7 +1059,7 @@ relay_client_outqueue_add (struct t_relay_client *client,
new_outqueue->data_size = data_size;
for (i = 0; i < 2; i++)
{
new_outqueue->raw_msg_type[i] = RELAY_CLIENT_MSG_STANDARD;
new_outqueue->raw_msg_type[i] = RELAY_MSG_STANDARD;
new_outqueue->raw_flags[i] = 0;
new_outqueue->raw_message[i] = NULL;
new_outqueue->raw_size[i] = 0;
@@ -1104,12 +1104,12 @@ relay_client_outqueue_add (struct t_relay_client *client,
int
relay_client_send (struct t_relay_client *client,
enum t_relay_client_msg_type msg_type,
enum t_relay_msg_type msg_type,
const char *data, int data_size,
const char *message_raw_buffer)
{
int num_sent, raw_size[2], raw_flags[2], opcode, i;
enum t_relay_client_msg_type raw_msg_type[2];
enum t_relay_msg_type raw_msg_type[2];
char *websocket_frame;
unsigned long long length_frame;
const char *ptr_data, *raw_msg[2];
@@ -1154,9 +1154,9 @@ relay_client_send (struct t_relay_client *client,
{
raw_msg[0] = data;
raw_size[0] = data_size;
if ((msg_type == RELAY_CLIENT_MSG_PING)
|| (msg_type == RELAY_CLIENT_MSG_PONG)
|| (msg_type == RELAY_CLIENT_MSG_CLOSE)
if ((msg_type == RELAY_MSG_PING)
|| (msg_type == RELAY_MSG_PONG)
|| (msg_type == RELAY_MSG_CLOSE)
|| ((client->websocket != RELAY_CLIENT_WEBSOCKET_INITIALIZING)
&& (client->send_data_type == RELAY_CLIENT_DATA_BINARY)))
{
@@ -1179,13 +1179,13 @@ relay_client_send (struct t_relay_client *client,
{
switch (msg_type)
{
case RELAY_CLIENT_MSG_PING:
case RELAY_MSG_PING:
opcode = WEBSOCKET_FRAME_OPCODE_PING;
break;
case RELAY_CLIENT_MSG_PONG:
case RELAY_MSG_PONG:
opcode = WEBSOCKET_FRAME_OPCODE_PONG;
break;
case RELAY_CLIENT_MSG_CLOSE:
case RELAY_MSG_CLOSE:
opcode = WEBSOCKET_FRAME_OPCODE_CLOSE;
break;
default:
@@ -1195,7 +1195,7 @@ relay_client_send (struct t_relay_client *client,
break;
}
websocket_frame = relay_websocket_encode_frame (
client, opcode, data, data_size, &length_frame);
client->ws_deflate, opcode, 0, data, data_size, &length_frame);
if (websocket_frame)
{
ptr_data = websocket_frame;
@@ -1223,8 +1223,9 @@ relay_client_send (struct t_relay_client *client,
{
if (raw_msg[i])
{
relay_raw_print (client, raw_msg_type[i], raw_flags[i],
raw_msg[i], raw_size[i]);
relay_raw_print_client (client, raw_msg_type[i],
raw_flags[i],
raw_msg[i], raw_size[i]);
}
}
if (num_sent > 0)
+1 -14
View File
@@ -50,18 +50,6 @@ enum t_relay_client_websocket_status
RELAY_NUM_CLIENT_WEBSOCKET_STATUS,
};
/* type of message exchanged with the client (used for websockets) */
enum t_relay_client_msg_type
{
RELAY_CLIENT_MSG_STANDARD,
RELAY_CLIENT_MSG_PING,
RELAY_CLIENT_MSG_PONG,
RELAY_CLIENT_MSG_CLOSE,
/* number of message types */
RELAY_NUM_CLIENT_MSG_TYPES,
};
/* fake send function (for tests) */
typedef void (t_relay_fake_send_func)(void *client,
@@ -127,7 +115,6 @@ struct t_relay_client
struct t_relay_client *next_client;/* link to next client */
};
extern char *relay_client_msg_type_string[];
extern struct t_relay_client *relay_clients;
extern struct t_relay_client *last_relay_client;
extern int relay_client_count;
@@ -141,7 +128,7 @@ extern void relay_client_recv_buffer (struct t_relay_client *client,
const char *buffer, int buffer_size);
extern int relay_client_recv_cb (const void *pointer, void *data, int fd);
extern int relay_client_send (struct t_relay_client *client,
enum t_relay_client_msg_type msg_type,
enum t_relay_msg_type msg_type,
const char *data,
int data_size, const char *message_raw_buffer);
extern int relay_client_timer_cb (const void *pointer, void *data,
+4 -20
View File
@@ -501,7 +501,6 @@ relay_command_remote (const void *pointer, void *data,
if (weechat_strcmp (argv[1], "add") == 0)
{
WEECHAT_COMMAND_MIN_ARGS(4, "add");
ptr_remote = relay_remote_search (argv[2]);
if (ptr_remote)
{
@@ -511,7 +510,6 @@ relay_command_remote (const void *pointer, void *data,
weechat_prefix ("error"), RELAY_PLUGIN_NAME, ptr_remote->name);
return WEECHAT_RC_OK;
}
if (!relay_remote_name_valid (argv[2]))
{
weechat_printf (NULL,
@@ -521,8 +519,6 @@ relay_command_remote (const void *pointer, void *data,
argv[2]);
return WEECHAT_RC_OK;
}
if (!relay_remote_url_valid (argv[3]))
{
weechat_printf (NULL,
@@ -532,11 +528,9 @@ relay_command_remote (const void *pointer, void *data,
argv[3]);
return WEECHAT_RC_OK;
}
ptr_proxy = NULL;
ptr_password = NULL;
ptr_totp_secret = NULL;
for (i = 4; i < argc; i++)
{
if (strncmp (argv[i], "-proxy=", 7) == 0)
@@ -561,7 +555,6 @@ relay_command_remote (const void *pointer, void *data,
return WEECHAT_RC_OK;
}
}
ptr_remote = relay_remote_new (argv[2], argv[3], ptr_proxy,
ptr_password, ptr_totp_secret);
if (ptr_remote)
@@ -576,14 +569,12 @@ relay_command_remote (const void *pointer, void *data,
weechat_prefix ("error"), RELAY_PLUGIN_NAME,
argv[2]);
}
return WEECHAT_RC_OK;
}
if (weechat_strcmp (argv[1], "connect") == 0)
{
WEECHAT_COMMAND_MIN_ARGS(3, "connect");
ptr_remote = relay_remote_search (argv[2]);
if (!ptr_remote)
{
@@ -596,14 +587,13 @@ relay_command_remote (const void *pointer, void *data,
"remote connect");
return WEECHAT_RC_OK;
}
WEECHAT_COMMAND_ERROR;
relay_remote_connect (ptr_remote);
return WEECHAT_RC_OK;
}
if (weechat_strcmp (argv[1], "rename") == 0)
{
WEECHAT_COMMAND_MIN_ARGS(4, "rename");
/* look for remote by name */
ptr_remote = relay_remote_search (argv[2]);
if (!ptr_remote)
@@ -617,7 +607,6 @@ relay_command_remote (const void *pointer, void *data,
"remote rename");
return WEECHAT_RC_OK;
}
/* check if target name already exists */
ptr_remote2 = relay_remote_search (argv[3]);
if (ptr_remote2)
@@ -631,7 +620,6 @@ relay_command_remote (const void *pointer, void *data,
"server rename");
return WEECHAT_RC_OK;
}
/* rename remote */
if (relay_remote_rename (ptr_remote, argv[3]))
{
@@ -643,14 +631,12 @@ relay_command_remote (const void *pointer, void *data,
argv[3]);
return WEECHAT_RC_OK;
}
WEECHAT_COMMAND_ERROR;
}
if (weechat_strcmp (argv[1], "disconnect") == 0)
{
WEECHAT_COMMAND_MIN_ARGS(3, "disconnect");
ptr_remote = relay_remote_search (argv[2]);
if (!ptr_remote)
{
@@ -663,14 +649,13 @@ relay_command_remote (const void *pointer, void *data,
"remote disconnect");
return WEECHAT_RC_OK;
}
WEECHAT_COMMAND_ERROR;
relay_remote_disconnect (ptr_remote);
return WEECHAT_RC_OK;
}
if (weechat_strcmp (argv[1], "del") == 0)
{
WEECHAT_COMMAND_MIN_ARGS(3, "del");
/* look for remote by name */
ptr_remote = relay_remote_search (argv[2]);
if (!ptr_remote)
@@ -705,7 +690,6 @@ relay_command_remote (const void *pointer, void *data,
(remote_name) ? remote_name : "???");
if (remote_name)
free (remote_name);
return WEECHAT_RC_OK;
}
+7 -7
View File
@@ -833,7 +833,7 @@ relay_http_process_websocket (struct t_relay_client *client)
if (handshake)
{
relay_client_send (client,
RELAY_CLIENT_MSG_STANDARD,
RELAY_MSG_STANDARD,
handshake,
strlen (handshake), NULL);
free (handshake);
@@ -877,10 +877,10 @@ relay_http_process_request (struct t_relay_client *client)
{
if (client->http_req->raw)
{
relay_raw_print (client, RELAY_CLIENT_MSG_STANDARD,
RELAY_RAW_FLAG_RECV,
*(client->http_req->raw),
strlen (*(client->http_req->raw)) + 1);
relay_raw_print_client (client, RELAY_MSG_STANDARD,
RELAY_RAW_FLAG_RECV,
*(client->http_req->raw),
strlen (*(client->http_req->raw)) + 1);
}
/* if websocket is initializing */
@@ -1199,7 +1199,7 @@ relay_http_send (struct t_relay_client *client,
if (!ptr_body || (*ptr_body_size <= 0))
{
num_bytes = relay_client_send (client, RELAY_CLIENT_MSG_STANDARD,
num_bytes = relay_client_send (client, RELAY_MSG_STANDARD,
str_header, length_header, NULL);
}
else
@@ -1227,7 +1227,7 @@ relay_http_send (struct t_relay_client *client,
{
raw_message = NULL;
}
num_bytes = relay_client_send (client, RELAY_CLIENT_MSG_STANDARD,
num_bytes = relay_client_send (client, RELAY_MSG_STANDARD,
http_message, length_msg,
raw_message);
if (raw_message)
+150 -98
View File
@@ -31,6 +31,7 @@
#include "relay-buffer.h"
#include "relay-client.h"
#include "relay-config.h"
#include "relay-remote.h"
struct t_gui_buffer *relay_raw_buffer = NULL;
@@ -234,77 +235,96 @@ relay_raw_message_add_to_list (time_t date, int date_usec,
return new_raw_message;
}
/*
* Converts a binary message for raw display.
*/
char *
relay_raw_convert_binary_message (const char *data, int data_size)
{
return weechat_string_hex_dump (data, data_size, 16, " > ", NULL);
}
/*
* Converts a text message for raw display.
*/
char *
relay_raw_convert_text_message (const char *data)
{
const unsigned char *ptr_buf;
const char *hexa = "0123456789ABCDEF";
char *buf, *buf2;
int i, pos_buf, pos_buf2, char_size;
buf = weechat_iconv_to_internal (NULL, data);
if (!buf)
return NULL;
buf2 = weechat_string_replace (buf, "\r", "");
free (buf);
if (!buf2)
return NULL;
buf = buf2;
buf2 = malloc ((strlen (buf) * 4) + 1);
if (buf2)
{
ptr_buf = (unsigned char *)buf;
pos_buf = 0;
pos_buf2 = 0;
while (ptr_buf[pos_buf])
{
if ((ptr_buf[pos_buf] < 32) && (ptr_buf[pos_buf] != '\n'))
{
buf2[pos_buf2++] = '\\';
buf2[pos_buf2++] = 'x';
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] / 16];
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] % 16];
pos_buf++;
}
else
{
char_size = weechat_utf8_char_size ((const char *)(ptr_buf + pos_buf));
for (i = 0; i < char_size; i++)
{
buf2[pos_buf2++] = ptr_buf[pos_buf++];
}
}
}
buf2[pos_buf2] = '\0';
}
free (buf);
return buf2;
}
/*
* Adds a new raw message to list.
*/
void
relay_raw_message_add (struct t_relay_client *client,
enum t_relay_client_msg_type msg_type,
relay_raw_message_add (enum t_relay_msg_type msg_type,
int flags,
const char *peer_id,
const char *data, int data_size)
{
char *buf, *buf2, *buf3, prefix[256], prefix_arrow[16];
const unsigned char *ptr_buf;
const char *hexa = "0123456789ABCDEF";
int pos_buf, pos_buf2, char_size, i, length;
char *raw_data, *buf, prefix[1024], prefix_arrow[16];
int length;
struct t_relay_raw_message *new_raw_message;
struct timeval tv_now;
buf = NULL;
buf2 = NULL;
buf3 = NULL;
if (flags & RELAY_RAW_FLAG_BINARY)
{
/* binary message */
buf = weechat_string_hex_dump (data, data_size, 16, " > ", NULL);
snprintf (prefix, sizeof (prefix), " ");
}
raw_data = relay_raw_convert_binary_message (data, data_size);
else
{
/* text message */
buf = weechat_iconv_to_internal (NULL, data);
buf2 = weechat_string_replace (buf, "\r", "");
if (buf2)
{
free (buf);
buf = buf2;
buf2 = NULL;
}
buf2 = malloc ((strlen (buf) * 4) + 1);
if (buf2)
{
ptr_buf = (buf) ? (unsigned char *)buf : (unsigned char *)data;
pos_buf = 0;
pos_buf2 = 0;
while (ptr_buf[pos_buf])
{
if ((ptr_buf[pos_buf] < 32) && (ptr_buf[pos_buf] != '\n'))
{
buf2[pos_buf2++] = '\\';
buf2[pos_buf2++] = 'x';
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] / 16];
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] % 16];
pos_buf++;
}
else
{
char_size = weechat_utf8_char_size ((const char *)(ptr_buf + pos_buf));
for (i = 0; i < char_size; i++)
{
buf2[pos_buf2++] = ptr_buf[pos_buf++];
}
}
}
buf2[pos_buf2] = '\0';
}
}
raw_data = relay_raw_convert_text_message (data);
if (!raw_data)
return;
snprintf (prefix, sizeof (prefix), " ");
if (!(flags & RELAY_RAW_FLAG_BINARY)
|| (msg_type == RELAY_CLIENT_MSG_PING)
|| (msg_type == RELAY_CLIENT_MSG_PONG)
|| (msg_type == RELAY_CLIENT_MSG_CLOSE))
|| (msg_type == RELAY_MSG_PING)
|| (msg_type == RELAY_MSG_PONG)
|| (msg_type == RELAY_MSG_CLOSE))
{
/* build prefix with arrow */
prefix_arrow[0] = '\0';
@@ -324,40 +344,22 @@ relay_raw_message_add (struct t_relay_client *client,
break;
}
if (client)
{
snprintf (prefix, sizeof (prefix), "%s%s %s[%s%d%s] %s%s%s%s",
(flags & RELAY_RAW_FLAG_SEND) ?
weechat_color ("chat_prefix_quit") :
weechat_color ("chat_prefix_join"),
prefix_arrow,
weechat_color ("chat_delimiters"),
weechat_color ("chat"),
client->id,
weechat_color ("chat_delimiters"),
weechat_color ("chat_server"),
relay_protocol_string[client->protocol],
(client->protocol_args) ? "." : "",
(client->protocol_args) ? client->protocol_args : "");
}
else
{
snprintf (prefix, sizeof (prefix), "%s%s",
(flags & RELAY_RAW_FLAG_SEND) ?
weechat_color ("chat_prefix_quit") :
weechat_color ("chat_prefix_join"),
prefix_arrow);
}
snprintf (prefix, sizeof (prefix), "%s%s%s%s",
(flags & RELAY_RAW_FLAG_SEND) ?
weechat_color ("chat_prefix_quit") :
weechat_color ("chat_prefix_join"),
prefix_arrow,
(peer_id && peer_id[0]) ? " " : "",
(peer_id && peer_id[0]) ? peer_id : "");
}
length = strlen (relay_client_msg_type_string[msg_type]) +
strlen ((buf2) ? buf2 : ((buf) ? buf : data)) + 1;
buf3 = malloc (length);
if (buf3)
length = strlen (relay_msg_type_string[msg_type]) + strlen (raw_data) + 1;
buf = malloc (length);
if (buf)
{
snprintf (buf3, length, "%s%s",
relay_client_msg_type_string[msg_type],
(buf2) ? buf2 : ((buf) ? buf : data));
snprintf (buf, length, "%s%s",
relay_msg_type_string[msg_type],
raw_data);
}
gettimeofday (&tv_now, NULL);
@@ -365,7 +367,7 @@ relay_raw_message_add (struct t_relay_client *client,
tv_now.tv_sec,
tv_now.tv_usec,
prefix,
(buf3) ? buf3 : ((buf2) ? buf2 : ((buf) ? buf : data)));
(buf) ? buf : raw_data);
if (new_raw_message)
{
@@ -377,26 +379,76 @@ relay_raw_message_add (struct t_relay_client *client,
if (buf)
free (buf);
if (buf2)
free (buf2);
if (buf3)
free (buf3);
free (raw_data);
}
/*
* Prints a message on relay raw buffer.
* Prints a message for a client on relay raw buffer.
*/
void
relay_raw_print (struct t_relay_client *client,
enum t_relay_client_msg_type msg_type, int flags,
const char *data, int data_size)
relay_raw_print_client (struct t_relay_client *client,
enum t_relay_msg_type msg_type,
int flags,
const char *data, int data_size)
{
/* auto-open Relay raw buffer if debug for irc plugin is >= 1 */
char peer_id[256];
/* auto-open relay raw buffer if debug for irc plugin is >= 1 */
if (!relay_raw_buffer && (weechat_relay_plugin->debug >= 1))
relay_raw_open (0);
relay_raw_message_add (client, msg_type, flags, data, data_size);
if (client)
{
snprintf (peer_id, sizeof (peer_id), "%s[%s%d%s] %s%s%s%s",
weechat_color ("chat_delimiters"),
weechat_color ("chat"),
client->id,
weechat_color ("chat_delimiters"),
weechat_color ("chat_server"),
relay_protocol_string[client->protocol],
(client->protocol_args) ? "." : "",
(client->protocol_args) ? client->protocol_args : "");
}
else
{
peer_id[0] = '\0';
}
relay_raw_message_add (msg_type, flags, peer_id, data, data_size);
}
/*
* Prints a message for a remote on relay raw buffer.
*/
void
relay_raw_print_remote (struct t_relay_remote *remote,
enum t_relay_msg_type msg_type,
int flags,
const char *data, int data_size)
{
char peer_id[256];
/* auto-open relay raw buffer if debug for irc plugin is >= 1 */
if (!relay_raw_buffer && (weechat_relay_plugin->debug >= 1))
relay_raw_open (0);
if (remote)
{
snprintf (peer_id, sizeof (peer_id), "%s<%sR%s> %s%s",
weechat_color ("chat_delimiters"),
weechat_color ("chat"),
weechat_color ("chat_delimiters"),
weechat_color ("chat_server"),
remote->name);
}
else
{
peer_id[0] = '\0';
}
relay_raw_message_add (msg_type, flags, peer_id, data, data_size);
}
/*
+8 -3
View File
@@ -32,6 +32,8 @@
#define RELAY_RAW_FLAG_SEND (1 << 1)
#define RELAY_RAW_FLAG_BINARY (1 << 2)
struct t_relay_remote;
struct t_relay_raw_message
{
time_t date; /* date/time of message */
@@ -53,9 +55,12 @@ extern struct t_relay_raw_message *relay_raw_message_add_to_list (time_t date,
int date_usec,
const char *prefix,
const char *message);
extern void relay_raw_print (struct t_relay_client *client,
enum t_relay_client_msg_type msg_type, int flags,
const char *data, int data_size);
extern void relay_raw_print_client (struct t_relay_client *client,
enum t_relay_msg_type msg_type, int flags,
const char *data, int data_size);
extern void relay_raw_print_remote (struct t_relay_remote *remote,
enum t_relay_msg_type msg_type, int flags,
const char *data, int data_size);
extern void relay_raw_message_free_all ();
extern int relay_raw_add_to_infolist (struct t_infolist *infolist,
struct t_relay_raw_message *raw_message);
+209 -16
View File
@@ -35,6 +35,10 @@
#include "relay.h"
#include "relay-config.h"
#include "relay-remote.h"
#include "relay-websocket.h"
#ifdef HAVE_CJSON
#include "api/remote/relay-remote-network.h"
#endif
char *relay_remote_option_string[RELAY_REMOTE_NUM_OPTIONS] =
@@ -225,6 +229,59 @@ relay_remote_send_signal (struct t_relay_remote *remote)
weechat_hook_signal_send (signal, WEECHAT_HOOK_SIGNAL_POINTER, remote);
}
/*
* Extracts address from URL.
*
* Note: result must be free after use.
*/
char *
relay_remote_get_address (const char *url)
{
const char *ptr_start;
char *pos;
if (!url)
return NULL;
if (strncmp (url, "http://", 7) == 0)
ptr_start = url + 7;
else if (strncmp (url, "https://", 8) == 0)
ptr_start = url + 8;
else
return NULL;
pos = strchr (ptr_start, ':');
return (pos) ?
weechat_strndup (ptr_start, pos - ptr_start) : strdup (ptr_start);
}
/*
* Extracts port from URL.
*/
int
relay_remote_get_port (const char *url)
{
char *pos, *error;
long port;
if (!url)
goto error;
pos = strrchr (url, ':');
if (!pos)
goto error;
error = NULL;
port = strtol (pos + 1, &error, 10);
if (error && !error[0])
return (int)port;
error:
return RELAY_REMOTE_DEFAULT_PORT;
}
/*
* Allocates and initializes new remote structure.
*
@@ -256,8 +313,16 @@ relay_remote_alloc (const char *name)
new_remote->port = 0;
new_remote->tls = 0;
new_remote->status = RELAY_STATUS_DISCONNECTED;
new_remote->password_hash_algo = -1;
new_remote->password_hash_iterations = -1;
new_remote->totp = -1;
new_remote->websocket_key = NULL;
new_remote->sock = -1;
new_remote->hook_url_handshake = NULL;
new_remote->hook_connect = NULL;
new_remote->hook_fd = NULL;
new_remote->gnutls_sess = NULL;
new_remote->ws_deflate = relay_websocket_deflate_alloc ();
new_remote->prev_remote = NULL;
new_remote->next_remote = NULL;
@@ -348,6 +413,11 @@ relay_remote_new_with_options (const char *name, struct t_config_option **option
new_remote->options[i] = options[i];
}
relay_remote_add (new_remote, &relay_remotes, &last_relay_remote);
new_remote->address = relay_remote_get_address (
weechat_config_string (new_remote->options[RELAY_REMOTE_OPTION_URL]));
new_remote->port = relay_remote_get_port (
weechat_config_string (new_remote->options[RELAY_REMOTE_OPTION_URL]));
relay_remotes_count++;
relay_remote_send_signal (new_remote);
@@ -409,6 +479,8 @@ struct t_relay_remote *
relay_remote_new_with_infolist (struct t_infolist *infolist)
{
struct t_relay_remote *new_remote;
Bytef *ptr_dict;
int dict_size;
new_remote = malloc (sizeof (*new_remote));
if (!new_remote)
@@ -419,8 +491,57 @@ relay_remote_new_with_infolist (struct t_infolist *infolist)
new_remote->port = weechat_infolist_integer (infolist, "port");
new_remote->tls = weechat_infolist_integer (infolist, "tls");
new_remote->status = weechat_infolist_integer (infolist, "status");
new_remote->password_hash_algo = weechat_infolist_integer (
infolist, "password_hash_algo");
new_remote->password_hash_iterations = weechat_infolist_integer (
infolist, "password_hash_iterations");
new_remote->totp = weechat_infolist_integer (infolist, "totp");
new_remote->websocket_key = strdup (weechat_infolist_string (infolist, "websocket_key"));
new_remote->sock = weechat_infolist_integer (infolist, "sock");
new_remote->hook_url_handshake = NULL;
new_remote->hook_connect = NULL;
new_remote->hook_fd = NULL;
new_remote->gnutls_sess = NULL;
new_remote->ws_deflate = relay_websocket_deflate_alloc ();
new_remote->ws_deflate->enabled = weechat_infolist_integer (infolist, "ws_deflate_enabled");
new_remote->ws_deflate->server_context_takeover = weechat_infolist_integer (infolist, "ws_deflate_server_context_takeover");
new_remote->ws_deflate->client_context_takeover = weechat_infolist_integer (infolist, "ws_deflate_client_context_takeover");
new_remote->ws_deflate->window_bits_deflate = weechat_infolist_integer (infolist, "ws_deflate_window_bits_deflate");
new_remote->ws_deflate->window_bits_inflate = weechat_infolist_integer (infolist, "ws_deflate_window_bits_inflate");
new_remote->ws_deflate->strm_deflate = NULL;
new_remote->ws_deflate->strm_inflate = NULL;
if (weechat_infolist_search_var (infolist, "ws_deflate_strm_deflate_dict"))
{
ptr_dict = weechat_infolist_buffer (infolist, "ws_deflate_strm_deflate_dict", &dict_size);
if (ptr_dict)
{
new_remote->ws_deflate->strm_deflate = calloc (1, sizeof (*new_remote->ws_deflate->strm_deflate));
if (new_remote->ws_deflate->strm_deflate)
{
if (relay_websocket_deflate_init_stream_deflate (new_remote->ws_deflate))
{
deflateSetDictionary (new_remote->ws_deflate->strm_deflate,
ptr_dict, dict_size);
}
}
}
}
if (weechat_infolist_search_var (infolist, "ws_deflate_strm_inflate_dict"))
{
ptr_dict = weechat_infolist_buffer (infolist, "ws_deflate_strm_inflate_dict", &dict_size);
if (ptr_dict)
{
new_remote->ws_deflate->strm_inflate = calloc (1, sizeof (*new_remote->ws_deflate->strm_inflate));
if (new_remote->ws_deflate->strm_inflate)
{
if (relay_websocket_deflate_init_stream_inflate (new_remote->ws_deflate))
{
inflateSetDictionary (new_remote->ws_deflate->strm_inflate,
ptr_dict, dict_size);
}
}
}
}
new_remote->prev_remote = NULL;
new_remote->next_remote = relay_remotes;
if (relay_remotes)
@@ -449,11 +570,39 @@ relay_remote_set_status (struct t_relay_remote *remote,
* a disconnected state for remote in infolist (used on /upgrade -save)
*/
if (remote->status == status)
return;
remote->status = status;
relay_remote_send_signal (remote);
}
/*
* Connects to a remote WeeChat relay/api.
*
* Returns:
* 1: OK
* 0: error
*/
int
relay_remote_connect (struct t_relay_remote *remote)
{
#ifndef HAVE_CJSON
weechat_printf (NULL,
_("%s%s: error: unable to connect to remote relay via API "
"(cJSON support is not enabled)"),
weechat_prefix ("error"), RELAY_PLUGIN_NAME);
return 0;
#endif /* HAVE_CJSON */
if (!remote)
return 0;
return relay_remote_network_connect (remote);
}
/*
* Renames a remote.
*
@@ -543,6 +692,7 @@ relay_remote_free (struct t_relay_remote *remote)
}
if (remote->address)
free (remote->address);
relay_websocket_deflate_free (remote->ws_deflate);
free (remote);
@@ -570,9 +720,7 @@ void
relay_remote_disconnect (struct t_relay_remote *remote)
{
if (remote->sock >= 0)
{
relay_remote_set_status (remote, RELAY_STATUS_DISCONNECTED);
}
relay_remote_network_disconnect (remote);
}
/*
@@ -609,6 +757,8 @@ relay_remote_add_to_infolist (struct t_infolist *infolist,
int force_disconnected_state)
{
struct t_infolist_item *ptr_item;
Bytef *dict;
uInt dict_size;
if (!infolist || !remote)
return 0;
@@ -625,6 +775,14 @@ relay_remote_add_to_infolist (struct t_infolist *infolist,
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "tls", remote->tls))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "password_hash_algo", remote->password_hash_algo))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "password_hash_iterations", remote->password_hash_iterations))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "totp", remote->totp))
return 0;
if (!weechat_infolist_new_var_string (ptr_item, "websocket_key", remote->websocket_key))
return 0;
if (!RELAY_STATUS_HAS_ENDED(remote->status) && force_disconnected_state)
{
if (!weechat_infolist_new_var_integer (ptr_item, "status", RELAY_STATUS_DISCONNECTED))
@@ -639,6 +797,33 @@ relay_remote_add_to_infolist (struct t_infolist *infolist,
if (!weechat_infolist_new_var_integer (ptr_item, "sock", remote->sock))
return 0;
}
if (remote->ws_deflate->strm_deflate || remote->ws_deflate->strm_inflate)
{
/* save the deflate/inflate dictionary, as it's required after /upgrade */
dict = malloc (32768);
if (dict)
{
if (remote->ws_deflate->strm_deflate)
{
if (deflateGetDictionary (remote->ws_deflate->strm_deflate, dict, &dict_size) == Z_OK)
{
weechat_infolist_new_var_buffer (ptr_item,
"ws_deflate_strm_deflate_dict",
dict, dict_size);
}
}
if (remote->ws_deflate->strm_inflate)
{
if (inflateGetDictionary (remote->ws_deflate->strm_inflate, dict, &dict_size) == Z_OK)
{
weechat_infolist_new_var_buffer (ptr_item,
"ws_deflate_strm_inflate_dict",
dict, dict_size);
}
}
free (dict);
}
}
return 1;
}
@@ -657,24 +842,32 @@ relay_remote_print_log ()
{
weechat_log_printf ("");
weechat_log_printf ("[relay remote (addr:0x%lx)]", ptr_remote);
weechat_log_printf (" name. . . . . . . . . : '%s'", ptr_remote->name);
weechat_log_printf (" url . . . . . . . . . : '%s'",
weechat_log_printf (" name. . . . . . . . . . : '%s'", ptr_remote->name);
weechat_log_printf (" url . . . . . . . . . . : '%s'",
weechat_config_string (ptr_remote->options[RELAY_REMOTE_OPTION_URL]));
weechat_log_printf (" proxy . . . . . . . . : '%s'",
weechat_log_printf (" proxy . . . . . . . . . : '%s'",
weechat_config_string (ptr_remote->options[RELAY_REMOTE_OPTION_PROXY]));
weechat_log_printf (" password. . . . . . . : '%s'",
weechat_log_printf (" password. . . . . . . . : '%s'",
weechat_config_string (ptr_remote->options[RELAY_REMOTE_OPTION_PASSWORD]));
weechat_log_printf (" totp_secret . . . . . : '%s'",
weechat_log_printf (" totp_secret . . . . . . : '%s'",
weechat_config_string (ptr_remote->options[RELAY_REMOTE_OPTION_TOTP_SECRET]));
weechat_log_printf (" address . . . . . . . : '%s'", ptr_remote->address);
weechat_log_printf (" port. . . . . . . . . : %d", ptr_remote->port);
weechat_log_printf (" tls . . . . . . . . . : %d", ptr_remote->tls);
weechat_log_printf (" status. . . . . . . . : %d (%s)",
weechat_log_printf (" address . . . . . . . . : '%s'", ptr_remote->address);
weechat_log_printf (" port. . . . . . . . . . : %d", ptr_remote->port);
weechat_log_printf (" tls . . . . . . . . . . : %d", ptr_remote->tls);
weechat_log_printf (" status. . . . . . . . . : %d (%s)",
ptr_remote->status,
relay_status_string[ptr_remote->status]);
weechat_log_printf (" sock. . . . . . . . . : %d", ptr_remote->sock);
weechat_log_printf (" gnutls_sess . . . . . : 0x%lx", ptr_remote->gnutls_sess);
weechat_log_printf (" prev_remote . . . . . : 0x%lx", ptr_remote->prev_remote);
weechat_log_printf (" next_remote . . . . . : 0x%lx", ptr_remote->next_remote);
weechat_log_printf (" password_hash_algo. . . : %d", ptr_remote->password_hash_algo);
weechat_log_printf (" password_hash_iterations: %d", ptr_remote->password_hash_iterations);
weechat_log_printf (" totp. . . . . . . . . . : %d", ptr_remote->totp);
weechat_log_printf (" websocket_key . . . . . : 0x%ls", ptr_remote->websocket_key);
weechat_log_printf (" sock. . . . . . . . . . : %d", ptr_remote->sock);
weechat_log_printf (" hook_url_handshake. . . : 0x%lx", ptr_remote->hook_url_handshake);
weechat_log_printf (" hook_connect. . . . . . : 0x%lx", ptr_remote->hook_connect);
weechat_log_printf (" hook_fd . . . . . . . . : 0x%lx", ptr_remote->hook_fd);
weechat_log_printf (" gnutls_sess . . . . . . : 0x%lx", ptr_remote->gnutls_sess);
relay_websocket_deflate_print_log (ptr_remote->ws_deflate, "");
weechat_log_printf (" prev_remote . . . . . . : 0x%lx", ptr_remote->prev_remote);
weechat_log_printf (" next_remote . . . . . . : 0x%lx", ptr_remote->next_remote);
}
}
+12
View File
@@ -22,6 +22,8 @@
#include <gnutls/gnutls.h>
#define RELAY_REMOTE_DEFAULT_PORT 9000
enum t_relay_remote_option
{
RELAY_REMOTE_OPTION_URL = 0, /* remote URL */
@@ -42,8 +44,17 @@ struct t_relay_remote
int port; /* port number */
int tls; /* 1 if TLS is enabled */
enum t_relay_status status; /* status (connecting, active,..) */
int password_hash_algo; /* hash algo (from handshake) */
int password_hash_iterations; /* hash iterations (from handshake) */
int totp; /* TOTP enabled (from handshake) */
char *websocket_key; /* random key sent to the remote */
/* in the websocket handshake */
int sock; /* connected socket */
struct t_hook *hook_url_handshake; /* URL hook for the handshake */
struct t_hook *hook_connect; /* connection hook */
struct t_hook *hook_fd; /* hook for socket */
gnutls_session_t gnutls_sess; /* gnutls session (only if TLS used) */
struct t_relay_websocket_deflate *ws_deflate; /* websocket deflate data */
struct t_relay_remote *prev_remote;/* link to previous remote */
struct t_relay_remote *next_remote;/* link to next remote */
};
@@ -76,6 +87,7 @@ extern struct t_relay_remote *relay_remote_new (const char *name,
extern struct t_relay_remote *relay_remote_new_with_infolist (struct t_infolist *infolist);
extern void relay_remote_set_status (struct t_relay_remote *remote,
enum t_relay_status status);
extern int relay_remote_connect (struct t_relay_remote *remote);
extern int relay_remote_rename (struct t_relay_remote *remote, const char *name);
extern void relay_remote_free (struct t_relay_remote *remote);
extern void relay_remote_free_all ();
+95 -60
View File
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <gcrypt.h>
#include <zlib.h>
#include "../weechat-plugin.h"
@@ -33,13 +34,6 @@
#include "relay-websocket.h"
/*
* globally unique identifier that is concatenated to HTTP header
* "Sec-WebSocket-Key"
*/
#define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
/*
* Allocates a t_relay_websocket_deflate structure.
*/
@@ -547,17 +541,23 @@ error:
* frame is first decompressed if "permessage-deflate" websocket extension
* is used).
*
* If argument "expect_masked_frame" is 1 and a frame is not masked,
* the function returns an error.
*
* Returns:
* 1: frame(s) decoded successfully
* 0: error decoding frame (connection must be closed if it happens)
*/
int
relay_websocket_decode_frame (struct t_relay_client *client,
const unsigned char *buffer,
relay_websocket_decode_frame (const unsigned char *buffer,
unsigned long long buffer_length,
int expect_masked_frame,
struct t_relay_websocket_deflate *ws_deflate,
struct t_relay_websocket_frame **frames,
int *num_frames)
int *num_frames,
char **partial_ws_frame,
int *partial_ws_frame_size)
{
unsigned long long i, index_buffer, index_buffer_start_frame;
unsigned long long length_frame_size, length_frame;
@@ -565,7 +565,7 @@ relay_websocket_decode_frame (struct t_relay_client *client,
size_t size_decompressed;
char *payload_decompressed;
struct t_relay_websocket_frame *frames2, *ptr_frame;
int size;
int size, masked_frame, mask[4];
if (!buffer || !frames || !num_frames)
return 0;
@@ -586,11 +586,15 @@ relay_websocket_decode_frame (struct t_relay_client *client,
opcode = buffer[index_buffer] & 15;
/* check if frame is masked */
masked_frame = (buffer[index_buffer + 1] & 128) ? 1 : 0;
/*
* check if frame is masked: client MUST send a masked frame; if frame is
* not masked, we MUST reject it and close the connection (see RFC 6455)
* error if the frame is not masked and we expect it to be masked,
* in this case we must reject it and close the connection
* (see RFC 6455)
*/
if (!(buffer[index_buffer + 1] & 128))
if (!masked_frame && expect_masked_frame)
return 0;
/* decode frame length */
@@ -611,15 +615,17 @@ relay_websocket_decode_frame (struct t_relay_client *client,
index_buffer += length_frame_size;
}
/* read masks (4 bytes) */
if (index_buffer + 4 > buffer_length)
goto missing_data;
int masks[4];
for (i = 0; i < 4; i++)
if (masked_frame)
{
masks[i] = (int)((unsigned char)buffer[index_buffer + i]);
/* read mask (4 bytes) */
if (index_buffer + 4 > buffer_length)
goto missing_data;
for (i = 0; i < 4; i++)
{
mask[i] = (int)((unsigned char)buffer[index_buffer + i]);
}
index_buffer += 4;
}
index_buffer += 4;
/* check if we have enough data */
if ((length_frame > buffer_length)
@@ -646,13 +652,13 @@ relay_websocket_decode_frame (struct t_relay_client *client,
switch (opcode)
{
case WEBSOCKET_FRAME_OPCODE_PING:
ptr_frame->opcode = RELAY_CLIENT_MSG_PING;
ptr_frame->opcode = RELAY_MSG_PING;
break;
case WEBSOCKET_FRAME_OPCODE_CLOSE:
ptr_frame->opcode = RELAY_CLIENT_MSG_CLOSE;
ptr_frame->opcode = RELAY_MSG_CLOSE;
break;
default:
ptr_frame->opcode = RELAY_CLIENT_MSG_STANDARD;
ptr_frame->opcode = RELAY_MSG_STANDARD;
break;
}
@@ -663,9 +669,16 @@ relay_websocket_decode_frame (struct t_relay_client *client,
ptr_frame->payload_size = length_frame;
/* fill payload */
for (i = 0; i < length_frame; i++)
if (masked_frame)
{
ptr_frame->payload[i] = (int)((unsigned char)buffer[index_buffer + i]) ^ masks[i % 4];
for (i = 0; i < length_frame; i++)
{
ptr_frame->payload[i] = (int)((unsigned char)buffer[index_buffer + i]) ^ mask[i % 4];
}
}
else
{
memcpy (ptr_frame->payload, buffer + index_buffer, length_frame);
}
ptr_frame->payload[length_frame] = '\0';
@@ -673,58 +686,58 @@ relay_websocket_decode_frame (struct t_relay_client *client,
* decompress data if frame is not empty and if "permessage-deflate"
* is enabled
*/
if ((length_frame > 0) && client->ws_deflate->enabled)
if ((length_frame > 0) && ws_deflate && ws_deflate->enabled)
{
if (!client->ws_deflate->strm_inflate)
if (!ws_deflate->strm_inflate)
{
client->ws_deflate->strm_inflate = calloc (
1, sizeof (*client->ws_deflate->strm_inflate));
if (!client->ws_deflate->strm_inflate)
ws_deflate->strm_inflate = calloc (
1, sizeof (*ws_deflate->strm_inflate));
if (!ws_deflate->strm_inflate)
return 0;
if (!relay_websocket_deflate_init_stream_inflate (client->ws_deflate))
if (!relay_websocket_deflate_init_stream_inflate (ws_deflate))
return 0;
}
payload_decompressed = relay_websocket_inflate (
ptr_frame->payload,
ptr_frame->payload_size,
client->ws_deflate->strm_inflate,
ws_deflate->strm_inflate,
&size_decompressed);
if (!payload_decompressed)
return 0;
free (ptr_frame->payload);
ptr_frame->payload = payload_decompressed;
ptr_frame->payload_size = size_decompressed;
if (!client->ws_deflate->client_context_takeover)
relay_websocket_deflate_free_stream_inflate (client->ws_deflate);
if (!ws_deflate->client_context_takeover)
relay_websocket_deflate_free_stream_inflate (ws_deflate);
}
index_buffer += length_frame;
}
if (client->partial_ws_frame)
if (*partial_ws_frame)
{
free (client->partial_ws_frame);
client->partial_ws_frame = NULL;
client->partial_ws_frame_size = 0;
free (*partial_ws_frame);
*partial_ws_frame = NULL;
*partial_ws_frame_size = 0;
}
return 1;
missing_data:
if (client->partial_ws_frame)
if (*partial_ws_frame)
{
free (client->partial_ws_frame);
client->partial_ws_frame = NULL;
client->partial_ws_frame_size = 0;
free (*partial_ws_frame);
*partial_ws_frame = NULL;
*partial_ws_frame_size = 0;
}
size = buffer_length - index_buffer_start_frame;
if (size >= 0)
{
client->partial_ws_frame = malloc (size);
if (!client->partial_ws_frame)
*partial_ws_frame = malloc (size);
if (!*partial_ws_frame)
return 0;
memcpy (client->partial_ws_frame, buffer + index_buffer_start_frame, size);
client->partial_ws_frame_size = size;
memcpy (*partial_ws_frame, buffer + index_buffer_start_frame, size);
*partial_ws_frame_size = size;
}
return 1;
}
@@ -779,12 +792,16 @@ relay_websocket_deflate (const void *data, size_t size, z_stream *strm,
* Returns websocket frame, NULL if error.
* Argument "length_frame" is set with the length of frame built.
*
* Argument "mask_frame" must be 1 when sending to server (remote) and 0 when
* sending to a client.
*
* Note: result must be freed after use.
*/
char *
relay_websocket_encode_frame (struct t_relay_client *client,
relay_websocket_encode_frame (struct t_relay_websocket_deflate *ws_deflate,
int opcode,
int mask_frame,
const char *payload,
unsigned long long payload_size,
unsigned long long *length_frame)
@@ -792,8 +809,8 @@ relay_websocket_encode_frame (struct t_relay_client *client,
const char *ptr_data;
char *payload_compressed;
size_t size_compressed;
unsigned char *frame;
unsigned long long index, data_size;
unsigned char *frame, *ptr_mask;
unsigned long long i, index, data_size;
*length_frame = 0;
@@ -810,21 +827,22 @@ relay_websocket_encode_frame (struct t_relay_client *client,
if (((opcode == WEBSOCKET_FRAME_OPCODE_TEXT)
|| (opcode == WEBSOCKET_FRAME_OPCODE_BINARY))
&& (payload_size > 0)
&& client->ws_deflate->enabled)
&& ws_deflate
&& ws_deflate->enabled)
{
if (!client->ws_deflate->strm_deflate)
if (!ws_deflate->strm_deflate)
{
client->ws_deflate->strm_deflate = calloc (
1, sizeof (*client->ws_deflate->strm_deflate));
if (!client->ws_deflate->strm_deflate)
ws_deflate->strm_deflate = calloc (
1, sizeof (*ws_deflate->strm_deflate));
if (!ws_deflate->strm_deflate)
return NULL;
if (!relay_websocket_deflate_init_stream_deflate (client->ws_deflate))
if (!relay_websocket_deflate_init_stream_deflate (ws_deflate))
return NULL;
}
payload_compressed = relay_websocket_deflate (
payload,
payload_size,
client->ws_deflate->strm_deflate,
ws_deflate->strm_deflate,
&size_compressed);
if (!payload_compressed)
return NULL;
@@ -838,13 +856,13 @@ relay_websocket_encode_frame (struct t_relay_client *client,
{
data_size -= 4;
}
if (!client->ws_deflate->server_context_takeover)
relay_websocket_deflate_free_stream_deflate (client->ws_deflate);
if (!ws_deflate->server_context_takeover)
relay_websocket_deflate_free_stream_deflate (ws_deflate);
/* set bit RSV1: indicate permessage-deflate compressed data */
opcode |= 0x40;
}
frame = malloc (data_size + 10);
frame = malloc (data_size + 14);
if (!frame)
{
if (payload_compressed)
@@ -884,9 +902,26 @@ relay_websocket_encode_frame (struct t_relay_client *client,
index = 10;
}
if (mask_frame)
{
frame[1] |= 128;
ptr_mask = frame + index;
gcry_create_nonce (ptr_mask, 4);
index += 4;
}
/* copy buffer after data_size */
memcpy (frame + index, ptr_data, data_size);
/* mask frame */
if (mask_frame)
{
for (i = 0; i < data_size; i++)
{
frame[index + i] = frame[index + i] ^ ptr_mask[i % 4];
}
}
*length_frame = index + data_size;
if (payload_compressed)
+14 -4
View File
@@ -24,6 +24,12 @@
#include <zlib.h>
/*
* globally unique identifier that is concatenated to HTTP header
* "Sec-WebSocket-Key"
*/
#define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
#define WEBSOCKET_FRAME_OPCODE_CONTINUATION 0x00
#define WEBSOCKET_FRAME_OPCODE_TEXT 0x01
#define WEBSOCKET_FRAME_OPCODE_BINARY 0x02
@@ -64,13 +70,17 @@ extern int relay_websocket_client_handshake_valid (struct t_relay_http_request *
extern void relay_websocket_parse_extensions (const char *extensions,
struct t_relay_websocket_deflate *ws_deflate);
extern char *relay_websocket_build_handshake (struct t_relay_http_request *request);
extern int relay_websocket_decode_frame (struct t_relay_client *client,
const unsigned char *buffer,
extern int relay_websocket_decode_frame (const unsigned char *buffer,
unsigned long long length,
int expect_masked_frame,
struct t_relay_websocket_deflate *ws_deflate,
struct t_relay_websocket_frame **frames,
int *num_frames);
extern char *relay_websocket_encode_frame (struct t_relay_client *client,
int *num_frames,
char **partial_ws_frame,
int *partial_ws_frame_size);
extern char *relay_websocket_encode_frame (struct t_relay_websocket_deflate *ws_deflate,
int opcode,
int mask_frame,
const char *payload,
unsigned long long payload_size,
unsigned long long *length_frame);
+2
View File
@@ -58,6 +58,8 @@ char *relay_status_name[] = /* name of status (for signal/info) */
{ "connecting", "waiting_auth",
"connected", "auth_failed", "disconnected"
};
char *relay_msg_type_string[] = /* prefix in raw buffer for msg */
{ "", "[PING]\n", "[PONG]\n", "[CLOSE]\n" };
struct t_hdata *relay_hdata_buffer = NULL;
struct t_hdata *relay_hdata_lines = NULL;
+13
View File
@@ -62,6 +62,18 @@ enum t_relay_status
RELAY_NUM_STATUS,
};
/* type of message exchanged with the peer (client/remote) */
enum t_relay_msg_type
{
RELAY_MSG_STANDARD,
RELAY_MSG_PING,
RELAY_MSG_PONG,
RELAY_MSG_CLOSE,
/* number of message types */
RELAY_NUM_MSG_TYPES,
};
#define RELAY_STATUS_HAS_ENDED(status) \
((status == RELAY_STATUS_AUTH_FAILED) || \
(status == RELAY_STATUS_DISCONNECTED))
@@ -74,6 +86,7 @@ enum t_relay_status
extern char *relay_protocol_string[];
extern char *relay_status_string[];
extern char *relay_status_name[];
extern char *relay_msg_type_string[];
extern int relay_protocol_search (const char *name);
extern int relay_status_search (const char *name);
@@ -1116,7 +1116,7 @@ relay_weechat_msg_compress_zlib (struct t_relay_client *client,
msg->id);
/* send compressed data */
relay_client_send (client, RELAY_CLIENT_MSG_STANDARD,
relay_client_send (client, RELAY_MSG_STANDARD,
(const char *)dest, dest_size + 5,
raw_message);
@@ -1189,7 +1189,7 @@ relay_weechat_msg_compress_zstd (struct t_relay_client *client,
msg->id);
/* send compressed data */
relay_client_send (client, RELAY_CLIENT_MSG_STANDARD,
relay_client_send (client, RELAY_MSG_STANDARD,
(const char *)dest, comp_size + 5,
raw_message);
@@ -1250,7 +1250,7 @@ relay_weechat_msg_send (struct t_relay_client *client,
/* send uncompressed data */
snprintf (raw_message, sizeof (raw_message),
"obj: %d bytes, id: %s", msg->data_size, msg->id);
relay_client_send (client, RELAY_CLIENT_MSG_STANDARD,
relay_client_send (client, RELAY_MSG_STANDARD,
msg->data, msg->data_size, raw_message);
}