Skip to content

Commit 68a9ea4

Browse files
Merge pull request #288 from paullouisageneau/fix-turn-server-filtering
Fix TURN server permissions enforcement when relaying
2 parents e5d541d + c98ede7 commit 68a9ea4

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

src/server.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,21 @@ int server_forward(juice_server_t *server, server_turn_alloc_t *alloc) {
478478
}
479479
addr_unmap_inet6_v4mapped((struct sockaddr *)&record.addr, &record.len);
480480

481+
// RFC 5766 8. Permissions:
482+
// When a UDP datagram arrives at the relayed transport address for the allocation, the
483+
// server extracts the source IP address from the IP header. The server then compares this
484+
// address with the IP address associated with each permission in the list of permissions
485+
// for the allocation. If no match is found, relaying is not permitted, and the server
486+
// silently discards the UDP datagram.
487+
if (!turn_has_permission(&alloc->map, &record)) {
488+
if (JLOG_DEBUG_ENABLED) {
489+
char record_str[ADDR_MAX_STRING_LEN];
490+
addr_record_to_string(&record, record_str, ADDR_MAX_STRING_LEN);
491+
JLOG_DEBUG("No permission for remote address %s, discarding", record_str);
492+
}
493+
return -1;
494+
}
495+
481496
uint16_t channel;
482497
if (turn_get_bound_channel(&alloc->map, &record, &channel)) {
483498
// Use ChannelData
@@ -1063,12 +1078,21 @@ int server_process_turn_channel_bind(juice_server_t *server, const stun_message_
10631078
credentials);
10641079
}
10651080

1081+
// RFC 5766 11.3. Receiving a ChannelBind Response
1082+
// When the client receives a ChannelBind success response, it updates its data structures to
1083+
// record that the channel binding is now active. It also updates its data structures to record
1084+
// that the corresponding permission has been installed or refreshed.
10661085
const addr_record_t *peer = msg->peers;
10671086
if (!turn_bind_channel(&alloc->map, peer, msg->transaction_id, channel, BIND_LIFETIME)) {
10681087
server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500,
10691088
credentials);
10701089
return -1;
10711090
}
1091+
if (!turn_set_permission(&alloc->map, msg->transaction_id, peer, PERMISSION_LIFETIME)) {
1092+
server_answer_stun_error(server, msg->transaction_id, src, msg->msg_method, 500,
1093+
credentials);
1094+
return -1;
1095+
}
10721096

10731097
stun_message_t ans;
10741098
memset(&ans, 0, sizeof(ans));
@@ -1105,7 +1129,11 @@ int server_process_turn_send(juice_server_t *server, const stun_message_t *msg,
11051129

11061130
const addr_record_t *peer = msg->peers;
11071131
if (!turn_has_permission(&alloc->map, peer)) {
1108-
JLOG_WARN("No permission for peer address");
1132+
if (JLOG_WARN_ENABLED) {
1133+
char peer_str[ADDR_MAX_STRING_LEN];
1134+
addr_record_to_string(peer, peer_str, ADDR_MAX_STRING_LEN);
1135+
JLOG_WARN("No permission for peer address %s", peer_str);
1136+
}
11091137
return -1;
11101138
}
11111139

src/turn.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,14 @@ static void delete_entry(turn_map_t *map, turn_entry_t *entry) {
156156
*/
157157
static turn_entry_t *find_entry(turn_map_t *map, const addr_record_t *record,
158158
turn_entry_type_t type, bool allow_deleted) {
159-
unsigned long key = (addr_record_hash(record, false) + (int)type) % map->map_size;
159+
// RFC 5766: only addresses are compared and port numbers are not considered.
160+
unsigned long key = (addr_record_hash(record, false /*no port*/) + (int)type) % map->map_size;
160161
unsigned long pos = key;
161162
while (true) {
162163
turn_entry_t *entry = map->map + pos;
163164
if (entry->type == TURN_ENTRY_TYPE_EMPTY ||
164-
(entry->type == type && addr_record_is_equal(&entry->record, record, false)))
165+
(entry->type == type &&
166+
addr_record_is_equal(&entry->record, record, false /*no port*/)))
165167
break;
166168

167169
if (allow_deleted && entry->type == TURN_ENTRY_TYPE_DELETED)
@@ -241,6 +243,13 @@ void turn_destroy_map(turn_map_t *map) {
241243

242244
bool turn_set_permission(turn_map_t *map, const uint8_t *transaction_id,
243245
const addr_record_t *record, timediff_t duration) {
246+
if (record) {
247+
if (JLOG_DEBUG_ENABLED) {
248+
char record_str[ADDR_MAX_STRING_LEN];
249+
addr_record_to_string(record, record_str, ADDR_MAX_STRING_LEN);
250+
JLOG_DEBUG("Updating TURN permission for address %s", record_str);
251+
}
252+
}
244253
return update_timestamp(map, TURN_ENTRY_TYPE_PERMISSION, transaction_id, record, duration);
245254
}
246255

@@ -254,6 +263,15 @@ bool turn_has_permission(turn_map_t *map, const addr_record_t *record) {
254263

255264
bool turn_bind_channel(turn_map_t *map, const addr_record_t *record, const uint8_t *transaction_id,
256265
uint16_t channel, timediff_t duration) {
266+
if(!record)
267+
return false;
268+
269+
if (JLOG_DEBUG_ENABLED) {
270+
char record_str[ADDR_MAX_STRING_LEN];
271+
addr_record_to_string(record, record_str, ADDR_MAX_STRING_LEN);
272+
JLOG_DEBUG("Binding TURN channel %hu to address %s", channel, record_str);
273+
}
274+
257275
if (!is_valid_channel(channel)) {
258276
JLOG_ERROR("Invalid channel number: 0x%hX", channel);
259277
return false;

0 commit comments

Comments
 (0)