Skip to content

Commit

Permalink
Merge pull request #286 from paullouisageneau/create-permission-multi…
Browse files Browse the repository at this point in the history
…ple-peers

Support multiple XOR-PEER-ADDRESS attributes in CreatePermission request
  • Loading branch information
paullouisageneau authored Jan 7, 2025
2 parents 70ba50c + 61a419e commit c3b8f1d
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 41 deletions.
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

0 comments on commit c3b8f1d

Please sign in to comment.