Skip to content

Commit 6fd8bce

Browse files
Support multiple XOR-PEER-ADDRESS attributes in CreatePermission request
1 parent 70ba50c commit 6fd8bce

File tree

4 files changed

+66
-38
lines changed

4 files changed

+66
-38
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: 21 additions & 11 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,7 +979,11 @@ 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");
983988
return -1;
984989
}
@@ -995,10 +1000,13 @@ int server_process_turn_create_permission(juice_server_t *server, const stun_mes
9951000
credentials);
9961001
}
9971002

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;
1003+
for (size_t i = 0; i < msg->peers_size; ++i) {
1004+
const addr_record_t *peer = msg->peers + i;
1005+
if (!turn_set_permission(&alloc->map, msg->transaction_id, peer, PERMISSION_LIFETIME)) {
1006+
server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500,
1007+
credentials);
1008+
return -1;
1009+
}
10021010
}
10031011

10041012
stun_message_t ans;
@@ -1020,7 +1028,7 @@ int server_process_turn_channel_bind(juice_server_t *server, const stun_message_
10201028

10211029
JLOG_DEBUG("Processing STUN ChannelBind request");
10221030

1023-
if (!msg->peer.len) {
1031+
if (!msg->peers_size) {
10241032
JLOG_WARN("Missing peer address in TURN ChannelBind request");
10251033
return -1;
10261034
}
@@ -1049,7 +1057,8 @@ int server_process_turn_channel_bind(juice_server_t *server, const stun_message_
10491057
credentials);
10501058
}
10511059

1052-
if (!turn_bind_channel(&alloc->map, &msg->peer, msg->transaction_id, channel, BIND_LIFETIME)) {
1060+
const addr_record_t *peer = msg->peers;
1061+
if (!turn_bind_channel(&alloc->map, peer, msg->transaction_id, channel, BIND_LIFETIME)) {
10531062
server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500,
10541063
credentials);
10551064
return -1;
@@ -1077,7 +1086,7 @@ int server_process_turn_send(juice_server_t *server, const stun_message_t *msg,
10771086
JLOG_WARN("Missing data in TURN Send indication");
10781087
return -1;
10791088
}
1080-
if (!msg->peer.len) {
1089+
if (!msg->peers_size) {
10811090
JLOG_WARN("Missing peer address in TURN Send indication");
10821091
return -1;
10831092
}
@@ -1088,14 +1097,15 @@ int server_process_turn_send(juice_server_t *server, const stun_message_t *msg,
10881097
return -1;
10891098
}
10901099

1091-
if (!turn_has_permission(&alloc->map, &msg->peer)) {
1100+
const addr_record_t *peer = msg->peers;
1101+
if (!turn_has_permission(&alloc->map, peer)) {
10921102
JLOG_WARN("No permission for peer address");
10931103
return -1;
10941104
}
10951105

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

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

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)