mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-03 03:20:57 +00:00
res_http_websocket: Add payload masking to the websocket client
ASTERISK-28949 Change-Id: Id465030f2b1997b83d408933fdbabe01827469ca
This commit is contained in:
committed by
Joshua Colp
parent
a3af7ef7e7
commit
635885ec33
@@ -290,28 +290,56 @@ int AST_OPTIONAL_API_NAME(ast_websocket_server_remove_protocol)(struct ast_webso
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Perform payload masking for client sessions */
|
||||
static void websocket_mask_payload(struct ast_websocket *session, char *frame, char *payload, uint64_t payload_size)
|
||||
{
|
||||
/* RFC 6455 5.1 - clients MUST mask frame data */
|
||||
if (session->client) {
|
||||
uint64_t i;
|
||||
uint8_t mask_key_idx;
|
||||
uint32_t mask_key = ast_random();
|
||||
uint8_t length = frame[1] & 0x7f;
|
||||
frame[1] |= 0x80; /* set mask bit to 1 */
|
||||
/* The mask key octet position depends on the length */
|
||||
mask_key_idx = length == 126 ? 4 : length == 127 ? 10 : 2;
|
||||
put_unaligned_uint32(&frame[mask_key_idx], mask_key);
|
||||
for (i = 0; i < payload_size; i++) {
|
||||
payload[i] ^= ((char *)&mask_key)[i % 4];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Close function for websocket session */
|
||||
int AST_OPTIONAL_API_NAME(ast_websocket_close)(struct ast_websocket *session, uint16_t reason)
|
||||
{
|
||||
enum ast_websocket_opcode opcode = AST_WEBSOCKET_OPCODE_CLOSE;
|
||||
char frame[4] = { 0, }; /* The header is 2 bytes and the reason code takes up another 2 bytes */
|
||||
int res;
|
||||
/* The header is either 2 or 6 bytes and the
|
||||
* reason code takes up another 2 bytes */
|
||||
char frame[8] = { 0, };
|
||||
int header_size, fsize, res;
|
||||
|
||||
if (session->close_sent) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* clients need space for an additional 4 byte masking key */
|
||||
header_size = session->client ? 6 : 2;
|
||||
fsize = header_size + 2;
|
||||
|
||||
frame[0] = opcode | 0x80;
|
||||
frame[1] = 2; /* The reason code is always 2 bytes */
|
||||
|
||||
/* If no reason has been specified assume 1000 which is normal closure */
|
||||
put_unaligned_uint16(&frame[2], htons(reason ? reason : 1000));
|
||||
put_unaligned_uint16(&frame[header_size], htons(reason ? reason : 1000));
|
||||
|
||||
websocket_mask_payload(session, frame, &frame[header_size], 2);
|
||||
|
||||
session->closing = 1;
|
||||
session->close_sent = 1;
|
||||
|
||||
ao2_lock(session);
|
||||
res = ast_careful_fwrite(session->f, session->fd, frame, 4, session->timeout);
|
||||
res = ast_careful_fwrite(session->f, session->fd, frame, fsize, session->timeout);
|
||||
|
||||
/* If an error occurred when trying to close this connection explicitly terminate it now.
|
||||
* Doing so will cause the thread polling on it to wake up and terminate.
|
||||
@@ -369,6 +397,11 @@ int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, en
|
||||
header_size += 8;
|
||||
}
|
||||
|
||||
if (session->client) {
|
||||
/* Additional 4 bytes for the client masking key */
|
||||
header_size += 4;
|
||||
}
|
||||
|
||||
frame_size = header_size + payload_size;
|
||||
|
||||
frame = ast_alloca(frame_size + 1);
|
||||
@@ -386,6 +419,8 @@ int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, en
|
||||
|
||||
memcpy(&frame[header_size], payload, payload_size);
|
||||
|
||||
websocket_mask_payload(session, frame, &frame[header_size], payload_size);
|
||||
|
||||
ao2_lock(session);
|
||||
if (session->closing) {
|
||||
ao2_unlock(session);
|
||||
|
Reference in New Issue
Block a user