Skip to content

Commit c3b8f1d

Browse files
Merge pull request #286 from paullouisageneau/create-permission-multiple-peers
Support multiple XOR-PEER-ADDRESS attributes in CreatePermission request
2 parents 70ba50c + 61a419e commit c3b8f1d

File tree

4 files changed

+75
-41
lines changed

4 files changed

+75
-41
lines changed

src/agent.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,8 @@ int agent_relay_send(juice_agent_t *agent, agent_stun_entry_t *entry, const addr
679679
msg.msg_class = STUN_CLASS_INDICATION;
680680
msg.msg_method = STUN_METHOD_SEND;
681681
juice_random(msg.transaction_id, STUN_TRANSACTION_ID_SIZE);
682-
msg.peer = *dst;
682+
msg.peers_size = 1;
683+
msg.peers[0] = *dst;
683684
msg.data = data;
684685
msg.data_size = size;
685686

@@ -1989,7 +1990,8 @@ int agent_send_turn_create_permission_request(juice_agent_t *agent, agent_stun_e
19891990
return -1;
19901991

19911992
msg.credentials = entry->turn->credentials;
1992-
msg.peer = *record;
1993+
msg.peers_size = 1;
1994+
msg.peers[0] = *record;
19931995

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

20942096
msg.credentials = entry->turn->credentials;
20952097
msg.channel_number = channel;
2096-
msg.peer = *record;
2098+
msg.peers_size = 1;
2099+
msg.peers[0] = *record;
20972100

20982101
if (out_channel)
20992102
*out_channel = channel;
@@ -2127,11 +2130,12 @@ int agent_process_turn_data(juice_agent_t *agent, const stun_message_t *msg,
21272130
JLOG_WARN("Missing data in TURN Data indication");
21282131
return -1;
21292132
}
2130-
if (!msg->peer.len) {
2133+
if (!msg->peers_size) {
21312134
JLOG_WARN("Missing peer address in TURN Data indication");
21322135
return -1;
21332136
}
2134-
return agent_input(agent, (char *)msg->data, msg->data_size, &msg->peer, &entry->relayed);
2137+
const addr_record_t *peer = msg->peers;
2138+
return agent_input(agent, (char *)msg->data, msg->data_size, peer, &entry->relayed);
21352139
}
21362140

21372141
int agent_process_channel_data(juice_agent_t *agent, agent_stun_entry_t *entry, char *buf,

src/server.c

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,8 @@ int server_forward(juice_server_t *server, server_turn_alloc_t *alloc) {
503503
memset(&msg, 0, sizeof(msg));
504504
msg.msg_class = STUN_CLASS_INDICATION;
505505
msg.msg_method = STUN_METHOD_DATA;
506-
msg.peer = record;
506+
msg.peers_size = 1;
507+
msg.peers[0] = record;
507508
msg.data = buffer;
508509
msg.data_size = len;
509510
juice_random(msg.transaction_id, STUN_TRANSACTION_ID_SIZE);
@@ -978,9 +979,15 @@ int server_process_turn_create_permission(juice_server_t *server, const stun_mes
978979

979980
JLOG_DEBUG("Processing STUN CreatePermission request");
980981

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

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

998-
if (!turn_set_permission(&alloc->map, msg->transaction_id, &msg->peer, PERMISSION_LIFETIME)) {
999-
server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500,
1000-
credentials);
1001-
return -1;
1005+
for (size_t i = 0; i < msg->peers_size; ++i) {
1006+
const addr_record_t *peer = msg->peers + i;
1007+
if (!turn_set_permission(&alloc->map, msg->transaction_id, peer, PERMISSION_LIFETIME)) {
1008+
server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500,
1009+
credentials);
1010+
return -1;
1011+
}
10021012
}
10031013

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

10211031
JLOG_DEBUG("Processing STUN ChannelBind request");
10221032

1023-
if (!msg->peer.len) {
1033+
if (!msg->peers_size) {
10241034
JLOG_WARN("Missing peer address in TURN ChannelBind request");
1025-
return -1;
1035+
return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method,
1036+
400, // Bad request
1037+
credentials);
10261038
}
10271039
if (!msg->channel_number) {
10281040
JLOG_WARN("Missing channel number in TURN ChannelBind request");
1029-
return -1;
1041+
return server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method,
1042+
400, // Bad request
1043+
credentials);
10301044
}
10311045

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

1052-
if (!turn_bind_channel(&alloc->map, &msg->peer, msg->transaction_id, channel, BIND_LIFETIME)) {
1066+
const addr_record_t *peer = msg->peers;
1067+
if (!turn_bind_channel(&alloc->map, peer, msg->transaction_id, channel, BIND_LIFETIME)) {
10531068
server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500,
10541069
credentials);
10551070
return -1;
@@ -1077,7 +1092,7 @@ int server_process_turn_send(juice_server_t *server, const stun_message_t *msg,
10771092
JLOG_WARN("Missing data in TURN Send indication");
10781093
return -1;
10791094
}
1080-
if (!msg->peer.len) {
1095+
if (!msg->peers_size) {
10811096
JLOG_WARN("Missing peer address in TURN Send indication");
10821097
return -1;
10831098
}
@@ -1088,14 +1103,15 @@ int server_process_turn_send(juice_server_t *server, const stun_message_t *msg,
10881103
return -1;
10891104
}
10901105

1091-
if (!turn_has_permission(&alloc->map, &msg->peer)) {
1106+
const addr_record_t *peer = msg->peers;
1107+
if (!turn_has_permission(&alloc->map, peer)) {
10921108
JLOG_WARN("No permission for peer address");
10931109
return -1;
10941110
}
10951111

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

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

src/stun.c

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -182,19 +182,22 @@ int stun_write(void *buf, size_t size, const stun_message_t *msg, const char *pa
182182
goto overflow;
183183
pos += len;
184184
}
185-
if (msg->peer.len) {
186-
JLOG_VERBOSE("Writing XOR peer address");
187-
uint8_t value[32];
188-
uint8_t mask[16];
189-
*((uint32_t *)mask) = htonl(STUN_MAGIC);
190-
memcpy(mask + 4, msg->transaction_id, 12);
191-
int value_len = stun_write_value_mapped_address(
192-
value, 32, (const struct sockaddr *)&msg->peer.addr, msg->peer.len, mask);
193-
if (value_len > 0) {
194-
len = stun_write_attr(pos, end - pos, STUN_ATTR_XOR_PEER_ADDRESS, value, value_len);
195-
if (len <= 0)
196-
goto overflow;
197-
pos += len;
185+
for (size_t i = 0; i < msg->peers_size; ++i) {
186+
const addr_record_t *peer = msg->peers + i;
187+
if (peer->len) {
188+
JLOG_VERBOSE("Writing XOR peer address");
189+
uint8_t value[32];
190+
uint8_t mask[16];
191+
*((uint32_t *)mask) = htonl(STUN_MAGIC);
192+
memcpy(mask + 4, msg->transaction_id, 12);
193+
int value_len = stun_write_value_mapped_address(
194+
value, 32, (const struct sockaddr *)&peer->addr, peer->len, mask);
195+
if (value_len > 0) {
196+
len = stun_write_attr(pos, end - pos, STUN_ATTR_XOR_PEER_ADDRESS, value, value_len);
197+
if (len <= 0)
198+
goto overflow;
199+
pos += len;
200+
}
198201
}
199202
}
200203
if (msg->relayed.len) {
@@ -908,7 +911,7 @@ int stun_read_attr(const void *data, size_t size, stun_message_t *msg, uint8_t *
908911
JLOG_DEBUG("STUN ICE controlling attribute length invalid, length=%zu", length);
909912
return -1;
910913
}
911-
uint32_t* value32 = (uint32_t *)attr->value;
914+
uint32_t *value32 = (uint32_t *)attr->value;
912915
msg->ice_controlling = ((uint64_t)ntohl(value32[0]) << 32) | ntohl(value32[1]);
913916
break;
914917
}
@@ -918,7 +921,7 @@ int stun_read_attr(const void *data, size_t size, stun_message_t *msg, uint8_t *
918921
JLOG_DEBUG("STUN ICE controlled attribute length invalid, length=%zu", length);
919922
return -1;
920923
}
921-
uint32_t* value32 = (uint32_t *)attr->value;
924+
uint32_t *value32 = (uint32_t *)attr->value;
922925
msg->ice_controlled = ((uint64_t)ntohl(value32[0]) << 32) | ntohl(value32[1]);
923926
break;
924927
}
@@ -945,11 +948,18 @@ int stun_read_attr(const void *data, size_t size, stun_message_t *msg, uint8_t *
945948
}
946949
case STUN_ATTR_XOR_PEER_ADDRESS: {
947950
JLOG_VERBOSE("Reading XOR peer address");
948-
uint8_t mask[16];
949-
*((uint32_t *)mask) = htonl(STUN_MAGIC);
950-
memcpy(mask + 4, msg->transaction_id, 12);
951-
if (stun_read_value_mapped_address(attr->value, length, &msg->peer, mask) < 0)
952-
return -1;
951+
if (msg->peers_size < STUN_MAX_PEER_ADDRESSES) {
952+
uint8_t mask[16];
953+
*((uint32_t *)mask) = htonl(STUN_MAGIC);
954+
memcpy(mask + 4, msg->transaction_id, 12);
955+
addr_record_t *peer = msg->peers + msg->peers_size;
956+
if (stun_read_value_mapped_address(attr->value, length, peer, mask) < 0)
957+
return -1;
958+
if (peer->len)
959+
++msg->peers_size;
960+
} else {
961+
JLOG_WARN("Too many STUN XOR-PEER-ADDRESS attributes, ignoring");
962+
}
953963
break;
954964
}
955965
case STUN_ATTR_XOR_RELAYED_ADDRESS: {
@@ -1004,7 +1014,7 @@ int stun_read_attr(const void *data, size_t size, stun_message_t *msg, uint8_t *
10041014
JLOG_DEBUG("STUN reservation token length invalid, length=%zu", length);
10051015
return -1;
10061016
}
1007-
uint32_t* value32 = (uint32_t *)attr->value;
1017+
uint32_t *value32 = (uint32_t *)attr->value;
10081018
msg->reservation_token = ((uint64_t)ntohl(value32[0]) << 32) | ntohl(value32[1]);
10091019
break;
10101020
}

src/stun.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,9 @@ typedef enum stun_password_algorithm {
297297

298298
#define STUN_MAX_PASSWORD_ALGORITHMS_VALUE_SIZE 256
299299

300+
// 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.
301+
#define STUN_MAX_PEER_ADDRESSES 8
302+
300303
typedef struct stun_credentials {
301304
char username[STUN_MAX_USERNAME_LEN];
302305
char realm[STUN_MAX_REALM_LEN];
@@ -326,7 +329,8 @@ typedef struct stun_message {
326329
bool has_fingerprint;
327330

328331
// TURN
329-
addr_record_t peer;
332+
addr_record_t peers[STUN_MAX_PEER_ADDRESSES];
333+
size_t peers_size;
330334
addr_record_t relayed;
331335
addr_record_t alternate_server;
332336
const char *data;

0 commit comments

Comments
 (0)