Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,8 @@ int agent_relay_send(juice_agent_t *agent, agent_stun_entry_t *entry, const addr
msg.msg_class = STUN_CLASS_INDICATION;
msg.msg_method = STUN_METHOD_SEND;
juice_random(msg.transaction_id, STUN_TRANSACTION_ID_SIZE);
msg.peer = *dst;
msg.peers_size = 1;
msg.peers[0] = *dst;
msg.data = data;
msg.data_size = size;

Expand Down Expand Up @@ -1989,7 +1990,8 @@ int agent_send_turn_create_permission_request(juice_agent_t *agent, agent_stun_e
return -1;

msg.credentials = entry->turn->credentials;
msg.peer = *record;
msg.peers_size = 1;
msg.peers[0] = *record;

char buffer[BUFFER_SIZE];
int size = stun_write(buffer, BUFFER_SIZE, &msg, entry->turn->password);
Expand Down Expand Up @@ -2093,7 +2095,8 @@ int agent_send_turn_channel_bind_request(juice_agent_t *agent, agent_stun_entry_

msg.credentials = entry->turn->credentials;
msg.channel_number = channel;
msg.peer = *record;
msg.peers_size = 1;
msg.peers[0] = *record;

if (out_channel)
*out_channel = channel;
Expand Down Expand Up @@ -2127,11 +2130,12 @@ int agent_process_turn_data(juice_agent_t *agent, const stun_message_t *msg,
JLOG_WARN("Missing data in TURN Data indication");
return -1;
}
if (!msg->peer.len) {
if (!msg->peers_size) {
JLOG_WARN("Missing peer address in TURN Data indication");
return -1;
}
return agent_input(agent, (char *)msg->data, msg->data_size, &msg->peer, &entry->relayed);
const addr_record_t *peer = msg->peers;
return agent_input(agent, (char *)msg->data, msg->data_size, peer, &entry->relayed);
}

int agent_process_channel_data(juice_agent_t *agent, agent_stun_entry_t *entry, char *buf,
Expand Down
44 changes: 30 additions & 14 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,8 @@ int server_forward(juice_server_t *server, server_turn_alloc_t *alloc) {
memset(&msg, 0, sizeof(msg));
msg.msg_class = STUN_CLASS_INDICATION;
msg.msg_method = STUN_METHOD_DATA;
msg.peer = record;
msg.peers_size = 1;
msg.peers[0] = record;
msg.data = buffer;
msg.data_size = len;
juice_random(msg.transaction_id, STUN_TRANSACTION_ID_SIZE);
Expand Down Expand Up @@ -978,9 +979,15 @@ int server_process_turn_create_permission(juice_server_t *server, const stun_mes

JLOG_DEBUG("Processing STUN CreatePermission request");

if (!msg->peer.len) {
// RFC 5766 9.2. Receiving a CreatePermission Request:
// The CreatePermission request MUST contain at least one XOR-PEER-ADDRESS attribute and MAY
// contain multiple such attributes. If no such attribute exists, or if any of these attributes
// are invalid, then a 400 (Bad Request) error is returned.
if (!msg->peers_size) {
JLOG_WARN("Missing peer address in TURN CreatePermission request");
return -1;
return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method,
400, // Bad request
credentials);
}

server_turn_alloc_t *alloc = find_allocation(server->allocs, server->allocs_count, src, false);
Expand All @@ -995,10 +1002,13 @@ int server_process_turn_create_permission(juice_server_t *server, const stun_mes
credentials);
}

if (!turn_set_permission(&alloc->map, msg->transaction_id, &msg->peer, PERMISSION_LIFETIME)) {
server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500,
credentials);
return -1;
for (size_t i = 0; i < msg->peers_size; ++i) {
const addr_record_t *peer = msg->peers + i;
if (!turn_set_permission(&alloc->map, msg->transaction_id, peer, PERMISSION_LIFETIME)) {
server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500,
credentials);
return -1;
}
}

stun_message_t ans;
Expand All @@ -1020,13 +1030,17 @@ int server_process_turn_channel_bind(juice_server_t *server, const stun_message_

JLOG_DEBUG("Processing STUN ChannelBind request");

if (!msg->peer.len) {
if (!msg->peers_size) {
JLOG_WARN("Missing peer address in TURN ChannelBind request");
return -1;
return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method,
400, // Bad request
credentials);
}
if (!msg->channel_number) {
JLOG_WARN("Missing channel number in TURN ChannelBind request");
return -1;
return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method,
400, // Bad request
credentials);
}

server_turn_alloc_t *alloc = find_allocation(server->allocs, server->allocs_count, src, false);
Expand All @@ -1049,7 +1063,8 @@ int server_process_turn_channel_bind(juice_server_t *server, const stun_message_
credentials);
}

if (!turn_bind_channel(&alloc->map, &msg->peer, msg->transaction_id, channel, BIND_LIFETIME)) {
const addr_record_t *peer = msg->peers;
if (!turn_bind_channel(&alloc->map, peer, msg->transaction_id, channel, BIND_LIFETIME)) {
server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500,
credentials);
return -1;
Expand Down Expand Up @@ -1077,7 +1092,7 @@ int server_process_turn_send(juice_server_t *server, const stun_message_t *msg,
JLOG_WARN("Missing data in TURN Send indication");
return -1;
}
if (!msg->peer.len) {
if (!msg->peers_size) {
JLOG_WARN("Missing peer address in TURN Send indication");
return -1;
}
Expand All @@ -1088,14 +1103,15 @@ int server_process_turn_send(juice_server_t *server, const stun_message_t *msg,
return -1;
}

if (!turn_has_permission(&alloc->map, &msg->peer)) {
const addr_record_t *peer = msg->peers;
if (!turn_has_permission(&alloc->map, peer)) {
JLOG_WARN("No permission for peer address");
return -1;
}

JLOG_VERBOSE("Forwarding datagram to peer, size=%zu", msg->data_size);

int ret = udp_sendto(alloc->sock, msg->data, msg->data_size, &msg->peer);
int ret = udp_sendto(alloc->sock, msg->data, msg->data_size, peer);
if (ret < 0 && sockerrno != SEAGAIN && sockerrno != SEWOULDBLOCK)
JLOG_WARN("Forwarding failed, errno=%d", sockerrno);

Expand Down
52 changes: 31 additions & 21 deletions src/stun.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,22 @@ int stun_write(void *buf, size_t size, const stun_message_t *msg, const char *pa
goto overflow;
pos += len;
}
if (msg->peer.len) {
JLOG_VERBOSE("Writing XOR peer address");
uint8_t value[32];
uint8_t mask[16];
*((uint32_t *)mask) = htonl(STUN_MAGIC);
memcpy(mask + 4, msg->transaction_id, 12);
int value_len = stun_write_value_mapped_address(
value, 32, (const struct sockaddr *)&msg->peer.addr, msg->peer.len, mask);
if (value_len > 0) {
len = stun_write_attr(pos, end - pos, STUN_ATTR_XOR_PEER_ADDRESS, value, value_len);
if (len <= 0)
goto overflow;
pos += len;
for (size_t i = 0; i < msg->peers_size; ++i) {
const addr_record_t *peer = msg->peers + i;
if (peer->len) {
JLOG_VERBOSE("Writing XOR peer address");
uint8_t value[32];
uint8_t mask[16];
*((uint32_t *)mask) = htonl(STUN_MAGIC);
memcpy(mask + 4, msg->transaction_id, 12);
int value_len = stun_write_value_mapped_address(
value, 32, (const struct sockaddr *)&peer->addr, peer->len, mask);
if (value_len > 0) {
len = stun_write_attr(pos, end - pos, STUN_ATTR_XOR_PEER_ADDRESS, value, value_len);
if (len <= 0)
goto overflow;
pos += len;
}
}
}
if (msg->relayed.len) {
Expand Down Expand Up @@ -908,7 +911,7 @@ int stun_read_attr(const void *data, size_t size, stun_message_t *msg, uint8_t *
JLOG_DEBUG("STUN ICE controlling attribute length invalid, length=%zu", length);
return -1;
}
uint32_t* value32 = (uint32_t *)attr->value;
uint32_t *value32 = (uint32_t *)attr->value;
msg->ice_controlling = ((uint64_t)ntohl(value32[0]) << 32) | ntohl(value32[1]);
break;
}
Expand All @@ -918,7 +921,7 @@ int stun_read_attr(const void *data, size_t size, stun_message_t *msg, uint8_t *
JLOG_DEBUG("STUN ICE controlled attribute length invalid, length=%zu", length);
return -1;
}
uint32_t* value32 = (uint32_t *)attr->value;
uint32_t *value32 = (uint32_t *)attr->value;
msg->ice_controlled = ((uint64_t)ntohl(value32[0]) << 32) | ntohl(value32[1]);
break;
}
Expand All @@ -945,11 +948,18 @@ int stun_read_attr(const void *data, size_t size, stun_message_t *msg, uint8_t *
}
case STUN_ATTR_XOR_PEER_ADDRESS: {
JLOG_VERBOSE("Reading XOR peer address");
uint8_t mask[16];
*((uint32_t *)mask) = htonl(STUN_MAGIC);
memcpy(mask + 4, msg->transaction_id, 12);
if (stun_read_value_mapped_address(attr->value, length, &msg->peer, mask) < 0)
return -1;
if (msg->peers_size < STUN_MAX_PEER_ADDRESSES) {
uint8_t mask[16];
*((uint32_t *)mask) = htonl(STUN_MAGIC);
memcpy(mask + 4, msg->transaction_id, 12);
addr_record_t *peer = msg->peers + msg->peers_size;
if (stun_read_value_mapped_address(attr->value, length, peer, mask) < 0)
return -1;
if (peer->len)
++msg->peers_size;
} else {
JLOG_WARN("Too many STUN XOR-PEER-ADDRESS attributes, ignoring");
}
break;
}
case STUN_ATTR_XOR_RELAYED_ADDRESS: {
Expand Down Expand Up @@ -1004,7 +1014,7 @@ int stun_read_attr(const void *data, size_t size, stun_message_t *msg, uint8_t *
JLOG_DEBUG("STUN reservation token length invalid, length=%zu", length);
return -1;
}
uint32_t* value32 = (uint32_t *)attr->value;
uint32_t *value32 = (uint32_t *)attr->value;
msg->reservation_token = ((uint64_t)ntohl(value32[0]) << 32) | ntohl(value32[1]);
break;
}
Expand Down
6 changes: 5 additions & 1 deletion src/stun.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,9 @@ typedef enum stun_password_algorithm {

#define STUN_MAX_PASSWORD_ALGORITHMS_VALUE_SIZE 256

// RFC 5766: When forming a CreatePermission request, the client MUST include at least one XOR-PEER-ADDRESS attribute, and MAY include more than one such attribute.
#define STUN_MAX_PEER_ADDRESSES 8

typedef struct stun_credentials {
char username[STUN_MAX_USERNAME_LEN];
char realm[STUN_MAX_REALM_LEN];
Expand Down Expand Up @@ -326,7 +329,8 @@ typedef struct stun_message {
bool has_fingerprint;

// TURN
addr_record_t peer;
addr_record_t peers[STUN_MAX_PEER_ADDRESSES];
size_t peers_size;
addr_record_t relayed;
addr_record_t alternate_server;
const char *data;
Expand Down
Loading