Line data Source code
1 : /*
2 : Copyright (c) 2007, Adobe Systems, Incorporated
3 : Copyright (c) 2013, Mozilla
4 :
5 : All rights reserved.
6 :
7 : Redistribution and use in source and binary forms, with or without
8 : modification, are permitted provided that the following conditions are
9 : met:
10 :
11 : * Redistributions of source code must retain the above copyright
12 : notice, this list of conditions and the following disclaimer.
13 :
14 : * Redistributions in binary form must reproduce the above copyright
15 : notice, this list of conditions and the following disclaimer in the
16 : documentation and/or other materials provided with the distribution.
17 :
18 : * Neither the name of Adobe Systems, Network Resonance, Mozilla nor
19 : the names of its contributors may be used to endorse or promote
20 : products derived from this software without specific prior written
21 : permission.
22 :
23 : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 : "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 : LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 : A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 : OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 : SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 : LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 : DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 : THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 : OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 : */
35 :
36 :
37 :
38 : static char *RCSSTRING __UNUSED__="$Id: turn_client_ctx.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
39 :
40 : #ifdef USE_TURN
41 :
42 : #include <assert.h>
43 : #include <string.h>
44 :
45 : #include "nr_api.h"
46 : #include "r_time.h"
47 : #include "async_timer.h"
48 : #include "nr_socket_buffered_stun.h"
49 : #include "stun.h"
50 : #include "turn_client_ctx.h"
51 :
52 : int NR_LOG_TURN = 0;
53 :
54 : #define TURN_MAX_PENDING_BYTES 32000
55 :
56 : #define TURN_RTO 100 /* Hardcoded RTO estimate */
57 : #define TURN_LIFETIME_REQUEST_SECONDS 3600 /* One hour */
58 : #define TURN_USECS_PER_S 1000000
59 : #define TURN_REFRESH_SLACK_SECONDS 10 /* How long before expiry to refresh
60 : allocations/permissions. The RFC 5766
61 : Section 7 recommendation if 60 seconds,
62 : but this is silly since the transaction
63 : times out after about 5. */
64 : #define TURN_PERMISSION_LIFETIME_SECONDS 300 /* 5 minutes. From RFC 5766 2.3 */
65 :
66 : // Set to enable a temporary fix that will run the TURN reservation keep-alive
67 : // logic when data is received via a TURN relayed path: a DATA_INDICATION packet is received.
68 : // TODO(pkerr@mozilla.com) This should be replace/removed when bug 935806 is implemented.
69 : #define REFRESH_RESERVATION_ON_RECV 1
70 :
71 : static int nr_turn_stun_ctx_create(nr_turn_client_ctx *tctx, int type,
72 : NR_async_cb success_cb,
73 : NR_async_cb failure_cb,
74 : nr_turn_stun_ctx **ctxp);
75 : static int nr_turn_stun_ctx_destroy(nr_turn_stun_ctx **ctxp);
76 : static void nr_turn_stun_ctx_cb(NR_SOCKET s, int how, void *arg);
77 : static int nr_turn_stun_set_auth_params(nr_turn_stun_ctx *ctx,
78 : char *realm, char *nonce);
79 : static void nr_turn_client_refresh_timer_cb(NR_SOCKET s, int how, void *arg);
80 : static int nr_turn_client_refresh_setup(nr_turn_client_ctx *ctx,
81 : nr_turn_stun_ctx **sctx);
82 : static int nr_turn_client_start_refresh_timer(nr_turn_client_ctx *ctx,
83 : nr_turn_stun_ctx *sctx,
84 : UINT4 lifetime);
85 : static int nr_turn_permission_create(nr_turn_client_ctx *ctx,
86 : nr_transport_addr *addr,
87 : nr_turn_permission **permp);
88 : static int nr_turn_permission_find(nr_turn_client_ctx *ctx,
89 : nr_transport_addr *addr,
90 : nr_turn_permission **permp);
91 : static int nr_turn_permission_destroy(nr_turn_permission **permp);
92 : static void nr_turn_client_refresh_cb(NR_SOCKET s, int how, void *arg);
93 : static void nr_turn_client_permissions_cb(NR_SOCKET s, int how, void *cb);
94 : static int nr_turn_client_send_stun_request(nr_turn_client_ctx *ctx,
95 : nr_stun_message *req,
96 : int flags);
97 :
98 :
99 : /* nr_turn_stun_ctx functions */
100 0 : static int nr_turn_stun_ctx_create(nr_turn_client_ctx *tctx, int mode,
101 : NR_async_cb success_cb,
102 : NR_async_cb error_cb,
103 : nr_turn_stun_ctx **ctxp)
104 : {
105 0 : nr_turn_stun_ctx *sctx = 0;
106 : int r,_status;
107 : char label[256];
108 :
109 0 : if (!(sctx=RCALLOC(sizeof(nr_turn_stun_ctx))))
110 0 : ABORT(R_NO_MEMORY);
111 :
112 : /* TODO(ekr@rtfm.com): label by phase */
113 0 : snprintf(label, sizeof(label), "%s:%s", tctx->label, ":TURN");
114 :
115 0 : if ((r=nr_stun_client_ctx_create(label, tctx->sock, &tctx->turn_server_addr,
116 0 : TURN_RTO, &sctx->stun))) {
117 0 : ABORT(r);
118 : }
119 :
120 : /* Set the STUN auth parameters, but don't set authentication on.
121 : For that we need the nonce, set in nr_turn_stun_set_auth_params.
122 : */
123 0 : sctx->stun->auth_params.username=tctx->username;
124 0 : INIT_DATA(sctx->stun->auth_params.password,
125 : tctx->password->data, tctx->password->len);
126 :
127 0 : sctx->tctx=tctx;
128 0 : sctx->success_cb=success_cb;
129 0 : sctx->error_cb=error_cb;
130 0 : sctx->mode=mode;
131 0 : sctx->last_error_code=0;
132 :
133 : /* Add ourselves to the tctx's list */
134 0 : STAILQ_INSERT_TAIL(&tctx->stun_ctxs, sctx, entry);
135 0 : *ctxp=sctx;
136 :
137 0 : _status=0;
138 : abort:
139 0 : if (_status) {
140 0 : nr_turn_stun_ctx_destroy(&sctx);
141 : }
142 0 : return(_status);
143 : }
144 :
145 : /* Note: this function does not pull us off the tctx's list. */
146 0 : static int nr_turn_stun_ctx_destroy(nr_turn_stun_ctx **ctxp)
147 : {
148 : nr_turn_stun_ctx *ctx;
149 :
150 0 : if (!ctxp || !*ctxp)
151 0 : return 0;
152 :
153 0 : ctx = *ctxp;
154 0 : *ctxp = 0;
155 :
156 0 : nr_stun_client_ctx_destroy(&ctx->stun);
157 0 : RFREE(ctx->realm);
158 0 : RFREE(ctx->nonce);
159 :
160 0 : RFREE(ctx);
161 :
162 0 : return 0;
163 : }
164 :
165 0 : static int nr_turn_stun_set_auth_params(nr_turn_stun_ctx *ctx,
166 : char *realm, char *nonce)
167 : {
168 : int _status;
169 :
170 0 : RFREE(ctx->realm);
171 0 : RFREE(ctx->nonce);
172 :
173 0 : assert(realm);
174 0 : if (!realm)
175 0 : ABORT(R_BAD_ARGS);
176 0 : ctx->realm=r_strdup(realm);
177 0 : if (!ctx->realm)
178 0 : ABORT(R_NO_MEMORY);
179 :
180 0 : assert(nonce);
181 0 : if (!nonce)
182 0 : ABORT(R_BAD_ARGS);
183 0 : ctx->nonce=r_strdup(nonce);
184 0 : if (!ctx->nonce)
185 0 : ABORT(R_NO_MEMORY);
186 :
187 0 : RFREE(ctx->stun->realm);
188 0 : ctx->stun->realm = r_strdup(ctx->realm);
189 0 : if (!ctx->stun->realm)
190 0 : ABORT(R_NO_MEMORY);
191 :
192 0 : ctx->stun->auth_params.realm = ctx->realm;
193 0 : ctx->stun->auth_params.nonce = ctx->nonce;
194 0 : ctx->stun->auth_params.authenticate = 1; /* May already be 1 */
195 :
196 0 : _status=0;
197 : abort:
198 0 : return(_status);
199 : }
200 :
201 0 : static int nr_turn_stun_ctx_start(nr_turn_stun_ctx *ctx)
202 : {
203 : int r, _status;
204 0 : nr_turn_client_ctx *tctx = ctx->tctx;
205 :
206 0 : if ((r=nr_stun_client_reset(ctx->stun))) {
207 0 : r_log(NR_LOG_TURN, LOG_ERR, "TURN(%s): Couldn't reset STUN",
208 : tctx->label);
209 0 : ABORT(r);
210 : }
211 :
212 0 : if ((r=nr_stun_client_start(ctx->stun, ctx->mode, nr_turn_stun_ctx_cb, ctx))) {
213 0 : r_log(NR_LOG_TURN, LOG_ERR, "TURN(%s): Couldn't start STUN",
214 : tctx->label);
215 0 : ABORT(r);
216 : }
217 :
218 0 : _status=0;
219 : abort:
220 0 : return _status;
221 : }
222 :
223 0 : static void nr_turn_stun_ctx_cb(NR_SOCKET s, int how, void *arg)
224 : {
225 : int r, _status;
226 0 : nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
227 :
228 0 : ctx->last_error_code = ctx->stun->error_code;
229 :
230 0 : switch (ctx->stun->state) {
231 : case NR_STUN_CLIENT_STATE_DONE:
232 : /* Save the realm and nonce */
233 0 : if (ctx->stun->realm && (!ctx->tctx->realm || strcmp(ctx->stun->realm,
234 0 : ctx->tctx->realm))) {
235 0 : RFREE(ctx->tctx->realm);
236 0 : ctx->tctx->realm = r_strdup(ctx->stun->realm);
237 0 : if (!ctx->tctx->realm)
238 0 : ABORT(R_NO_MEMORY);
239 : }
240 0 : if (ctx->stun->nonce && (!ctx->tctx->nonce || strcmp(ctx->stun->nonce,
241 0 : ctx->tctx->nonce))) {
242 0 : RFREE(ctx->tctx->nonce);
243 0 : ctx->tctx->nonce = r_strdup(ctx->stun->nonce);
244 0 : if (!ctx->tctx->nonce)
245 0 : ABORT(R_NO_MEMORY);
246 : }
247 :
248 0 : ctx->retry_ct=0;
249 0 : ctx->success_cb(0, 0, ctx);
250 0 : break;
251 :
252 : case NR_STUN_CLIENT_STATE_FAILED:
253 : /* Special case: if this is an authentication error,
254 : we retry once. This allows the 401/438 nonce retry
255 : paradigm. After that, we fail */
256 : /* TODO(ekr@rtfm.com): 401 needs a #define */
257 : /* TODO(ekr@rtfm.com): Add alternate-server (Mozilla bug 857688) */
258 0 : if (ctx->stun->error_code == 438) {
259 : // track 438s for ice telemetry
260 0 : nr_ice_accumulate_count(&(ctx->tctx->cnt_438s), 1);
261 : }
262 0 : if (ctx->stun->error_code == 401 || ctx->stun->error_code == 438) {
263 0 : if (ctx->retry_ct > 0) {
264 0 : if (ctx->stun->error_code == 401) {
265 : // track 401s for ice telemetry
266 0 : nr_ice_accumulate_count(&(ctx->tctx->cnt_401s), 1);
267 : }
268 0 : r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): Exceeded the number of retries", ctx->tctx->label);
269 0 : ABORT(R_FAILED);
270 : }
271 :
272 0 : if (!ctx->stun->nonce) {
273 0 : r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): 401 but no nonce", ctx->tctx->label);
274 0 : ABORT(R_FAILED);
275 : }
276 0 : if (!ctx->stun->realm) {
277 0 : r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): 401 but no realm", ctx->tctx->label);
278 0 : ABORT(R_FAILED);
279 : }
280 :
281 : /* Try to retry */
282 0 : if ((r=nr_turn_stun_set_auth_params(ctx, ctx->stun->realm,
283 0 : ctx->stun->nonce)))
284 0 : ABORT(r);
285 :
286 0 : ctx->stun->error_code = 0; /* Reset to avoid inf-looping */
287 :
288 0 : if ((r=nr_turn_stun_ctx_start(ctx))) {
289 0 : r_log(NR_LOG_TURN, LOG_ERR, "TURN(%s): Couldn't start STUN", ctx->tctx->label);
290 0 : ABORT(r);
291 : }
292 :
293 0 : ctx->retry_ct++;
294 : }
295 : else {
296 0 : ABORT(R_FAILED);
297 : }
298 0 : break;
299 :
300 : case NR_STUN_CLIENT_STATE_TIMED_OUT:
301 0 : ABORT(R_FAILED);
302 : break;
303 :
304 : case NR_STUN_CLIENT_STATE_CANCELLED:
305 0 : assert(0); /* Shouldn't happen */
306 : return;
307 : break;
308 :
309 : default:
310 0 : assert(0); /* Shouldn't happen */
311 : return;
312 : }
313 :
314 0 : _status=0;
315 : abort:
316 0 : if (_status) {
317 0 : ctx->error_cb(0, 0, ctx);
318 : }
319 0 : }
320 :
321 : /* nr_turn_client_ctx functions */
322 0 : int nr_turn_client_ctx_create(const char *label, nr_socket *sock,
323 : const char *username, Data *password,
324 : nr_transport_addr *addr,
325 : nr_turn_client_ctx **ctxp)
326 : {
327 0 : nr_turn_client_ctx *ctx=0;
328 : int r,_status;
329 :
330 0 : if ((r=r_log_register("turn", &NR_LOG_TURN)))
331 0 : ABORT(r);
332 :
333 0 : if(!(ctx=RCALLOC(sizeof(nr_turn_client_ctx))))
334 0 : ABORT(R_NO_MEMORY);
335 :
336 0 : STAILQ_INIT(&ctx->stun_ctxs);
337 0 : STAILQ_INIT(&ctx->permissions);
338 :
339 0 : if(!(ctx->label=r_strdup(label)))
340 0 : ABORT(R_NO_MEMORY);
341 :
342 0 : ctx->sock=sock;
343 0 : ctx->username = r_strdup(username);
344 0 : if (!ctx->username)
345 0 : ABORT(R_NO_MEMORY);
346 :
347 0 : if ((r=r_data_create(&ctx->password, password->data, password->len)))
348 0 : ABORT(r);
349 0 : if ((r=nr_transport_addr_copy(&ctx->turn_server_addr, addr)))
350 0 : ABORT(r);
351 :
352 0 : ctx->state = NR_TURN_CLIENT_STATE_INITTED;
353 0 : if (addr->protocol == IPPROTO_TCP) {
354 0 : if ((r=nr_socket_connect(ctx->sock, &ctx->turn_server_addr))) {
355 0 : if (r != R_WOULDBLOCK)
356 0 : ABORT(r);
357 : }
358 : }
359 :
360 0 : *ctxp=ctx;
361 :
362 0 : _status=0;
363 : abort:
364 0 : if(_status){
365 0 : nr_turn_client_ctx_destroy(&ctx);
366 : }
367 0 : return(_status);
368 : }
369 :
370 : int
371 0 : nr_turn_client_ctx_destroy(nr_turn_client_ctx **ctxp)
372 : {
373 : nr_turn_client_ctx *ctx;
374 :
375 0 : if(!ctxp || !*ctxp)
376 0 : return(0);
377 :
378 0 : ctx=*ctxp;
379 0 : *ctxp = 0;
380 :
381 0 : if (ctx->label)
382 0 : r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): destroy", ctx->label);
383 :
384 0 : nr_turn_client_deallocate(ctx);
385 :
386 : /* Cancel frees the rest of our data */
387 0 : RFREE(ctx->label);
388 0 : ctx->label = 0;
389 :
390 0 : nr_turn_client_cancel(ctx);
391 :
392 0 : RFREE(ctx->username);
393 0 : ctx->username = 0;
394 0 : r_data_destroy(&ctx->password);
395 0 : RFREE(ctx->nonce);
396 0 : ctx->nonce = 0;
397 0 : RFREE(ctx->realm);
398 0 : ctx->realm = 0;
399 :
400 : /* Destroy the STUN client ctxs */
401 0 : while (!STAILQ_EMPTY(&ctx->stun_ctxs)) {
402 0 : nr_turn_stun_ctx *stun = STAILQ_FIRST(&ctx->stun_ctxs);
403 0 : STAILQ_REMOVE_HEAD(&ctx->stun_ctxs, entry);
404 0 : nr_turn_stun_ctx_destroy(&stun);
405 : }
406 :
407 : /* Destroy the permissions */
408 0 : while (!STAILQ_EMPTY(&ctx->permissions)) {
409 0 : nr_turn_permission *perm = STAILQ_FIRST(&ctx->permissions);
410 0 : STAILQ_REMOVE_HEAD(&ctx->permissions, entry);
411 0 : nr_turn_permission_destroy(&perm);
412 : }
413 :
414 0 : RFREE(ctx);
415 :
416 0 : return(0);
417 : }
418 :
419 0 : int nr_turn_client_cancel(nr_turn_client_ctx *ctx)
420 : {
421 0 : nr_turn_stun_ctx *stun = 0;
422 :
423 0 : if (ctx->state == NR_TURN_CLIENT_STATE_CANCELLED ||
424 0 : ctx->state == NR_TURN_CLIENT_STATE_FAILED)
425 0 : return(0);
426 :
427 0 : if (ctx->label)
428 0 : r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): cancelling", ctx->label);
429 :
430 : /* Cancel the STUN client ctxs */
431 0 : stun = STAILQ_FIRST(&ctx->stun_ctxs);
432 0 : while (stun) {
433 0 : nr_stun_client_cancel(stun->stun);
434 0 : stun = STAILQ_NEXT(stun, entry);
435 : }
436 :
437 : /* Cancel the timers, if not already cancelled */
438 0 : NR_async_timer_cancel(ctx->connected_timer_handle);
439 0 : NR_async_timer_cancel(ctx->refresh_timer_handle);
440 :
441 0 : ctx->state = NR_TURN_CLIENT_STATE_CANCELLED;
442 :
443 0 : return(0);
444 : }
445 :
446 0 : int nr_turn_client_send_stun_request(nr_turn_client_ctx *ctx,
447 : nr_stun_message *req,
448 : int flags)
449 : {
450 : int r,_status;
451 :
452 0 : if ((r=nr_stun_encode_message(req)))
453 0 : ABORT(r);
454 :
455 0 : if ((r=nr_socket_sendto(ctx->sock,
456 0 : req->buffer, req->length, flags,
457 : &ctx->turn_server_addr))) {
458 0 : r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): Failed sending request",
459 : ctx->label);
460 0 : ABORT(r);
461 : }
462 :
463 0 : _status=0;
464 : abort:
465 0 : return(_status);
466 : }
467 :
468 0 : int nr_turn_client_deallocate(nr_turn_client_ctx *ctx)
469 : {
470 : int r,_status;
471 0 : nr_stun_message *aloc = 0;
472 : nr_stun_client_auth_params auth;
473 : nr_stun_client_refresh_request_params refresh;
474 :
475 0 : if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
476 0 : return(0);
477 :
478 0 : r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): deallocating", ctx->label);
479 :
480 0 : refresh.lifetime_secs = 0;
481 :
482 0 : auth.username = ctx->username;
483 0 : INIT_DATA(auth.password, ctx->password->data, ctx->password->len);
484 :
485 0 : auth.realm = ctx->realm;
486 0 : auth.nonce = ctx->nonce;
487 :
488 0 : auth.authenticate = 1;
489 :
490 0 : if ((r=nr_stun_build_refresh_request(&auth, &refresh, &aloc)))
491 0 : ABORT(r);
492 :
493 : // We are only sending a single request here because we are in the process of
494 : // shutting everything down. Theoretically we should probably start a seperate
495 : // STUN transaction which outlives the TURN context.
496 0 : if ((r=nr_turn_client_send_stun_request(ctx, aloc, 0)))
497 0 : ABORT(r);
498 :
499 0 : ctx->state = NR_TURN_CLIENT_STATE_DEALLOCATING;
500 :
501 0 : _status=0;
502 : abort:
503 0 : nr_stun_message_destroy(&aloc);
504 0 : return(_status);
505 : }
506 :
507 0 : static void nr_turn_client_fire_finished_cb(nr_turn_client_ctx *ctx)
508 : {
509 0 : if (ctx->finished_cb) {
510 0 : NR_async_cb finished_cb=ctx->finished_cb;
511 0 : ctx->finished_cb=0;
512 0 : finished_cb(0, 0, ctx->cb_arg);
513 : }
514 0 : }
515 :
516 0 : int nr_turn_client_failed(nr_turn_client_ctx *ctx)
517 : {
518 0 : if (ctx->state == NR_TURN_CLIENT_STATE_FAILED ||
519 0 : ctx->state == NR_TURN_CLIENT_STATE_CANCELLED)
520 0 : return(0);
521 :
522 0 : r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s) failed", ctx->label);
523 0 : nr_turn_client_cancel(ctx);
524 0 : ctx->state = NR_TURN_CLIENT_STATE_FAILED;
525 0 : nr_turn_client_fire_finished_cb(ctx);
526 :
527 0 : return(0);
528 : }
529 :
530 0 : int nr_turn_client_get_relayed_address(nr_turn_client_ctx *ctx,
531 : nr_transport_addr *relayed_address)
532 : {
533 : int r, _status;
534 :
535 0 : if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
536 0 : ABORT(R_FAILED);
537 :
538 0 : if (r=nr_transport_addr_copy(relayed_address, &ctx->relay_addr))
539 0 : ABORT(r);
540 :
541 0 : _status=0;
542 : abort:
543 0 : return(_status);
544 : }
545 :
546 0 : int nr_turn_client_get_mapped_address(nr_turn_client_ctx *ctx,
547 : nr_transport_addr *mapped_address)
548 : {
549 : int r, _status;
550 :
551 0 : if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
552 0 : ABORT(R_FAILED);
553 :
554 0 : if (r=nr_transport_addr_copy(mapped_address, &ctx->mapped_addr))
555 0 : ABORT(r);
556 :
557 0 : _status=0;
558 : abort:
559 0 : return(_status);
560 : }
561 :
562 0 : static void nr_turn_client_allocate_cb(NR_SOCKET s, int how, void *arg)
563 : {
564 0 : nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
565 : nr_turn_stun_ctx *refresh_ctx;
566 : int r,_status;
567 :
568 0 : ctx->tctx->state = NR_TURN_CLIENT_STATE_ALLOCATED;
569 :
570 0 : if ((r=nr_transport_addr_copy(
571 0 : &ctx->tctx->relay_addr,
572 0 : &ctx->stun->results.allocate_response.relay_addr)))
573 0 : ABORT(r);
574 :
575 0 : if ((r=nr_transport_addr_copy(
576 0 : &ctx->tctx->mapped_addr,
577 0 : &ctx->stun->results.allocate_response.mapped_addr)))
578 0 : ABORT(r);
579 :
580 0 : if ((r=nr_turn_client_refresh_setup(ctx->tctx, &refresh_ctx)))
581 0 : ABORT(r);
582 :
583 0 : if ((r=nr_turn_client_start_refresh_timer(
584 0 : ctx->tctx, refresh_ctx,
585 0 : ctx->stun->results.allocate_response.lifetime_secs)))
586 0 : ABORT(r);
587 :
588 0 : r_log(NR_LOG_TURN, LOG_INFO,
589 : "TURN(%s): Succesfully allocated addr %s lifetime=%u",
590 0 : ctx->tctx->label,
591 0 : ctx->tctx->relay_addr.as_string,
592 0 : ctx->stun->results.allocate_response.lifetime_secs);
593 :
594 0 : nr_turn_client_fire_finished_cb(ctx->tctx);
595 0 : _status=0;
596 : abort:
597 0 : if (_status) {
598 0 : nr_turn_client_failed(ctx->tctx);
599 : }
600 0 : }
601 :
602 0 : static void nr_turn_client_error_cb(NR_SOCKET s, int how, void *arg)
603 : {
604 0 : nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
605 :
606 0 : r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): mode %d, %s",
607 0 : ctx->tctx->label, ctx->mode, __FUNCTION__);
608 :
609 0 : nr_turn_client_failed(ctx->tctx);
610 0 : }
611 :
612 0 : static void nr_turn_client_permission_error_cb(NR_SOCKET s, int how, void *arg)
613 : {
614 0 : nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
615 :
616 0 : if (ctx->last_error_code == 403) {
617 : // track 403s for ice telemetry
618 0 : nr_ice_accumulate_count(&(ctx->tctx->cnt_403s), 1);
619 0 : r_log(NR_LOG_TURN, LOG_WARNING, "TURN(%s): mode %d, permission denied",
620 0 : ctx->tctx->label, ctx->mode);
621 :
622 : } else{
623 0 : nr_turn_client_error_cb(0, 0, ctx);
624 : }
625 0 : }
626 :
627 0 : int nr_turn_client_allocate(nr_turn_client_ctx *ctx,
628 : NR_async_cb finished_cb, void *cb_arg)
629 : {
630 0 : nr_turn_stun_ctx *stun = 0;
631 : int r,_status;
632 :
633 0 : if(ctx->state == NR_TURN_CLIENT_STATE_FAILED ||
634 0 : ctx->state == NR_TURN_CLIENT_STATE_CANCELLED){
635 : /* TURN TCP contexts can fail before we ever try to form an allocation,
636 : * since the TCP connection can fail. It is also conceivable that a TURN
637 : * TCP context could be cancelled before we are done forming all
638 : * allocations (although we do not do this at the time this code was
639 : * written) */
640 0 : assert(ctx->turn_server_addr.protocol == IPPROTO_TCP);
641 0 : ABORT(R_NOT_FOUND);
642 : }
643 :
644 0 : assert(ctx->state == NR_TURN_CLIENT_STATE_INITTED);
645 :
646 0 : ctx->finished_cb=finished_cb;
647 0 : ctx->cb_arg=cb_arg;
648 :
649 0 : if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST,
650 : nr_turn_client_allocate_cb,
651 : nr_turn_client_error_cb,
652 : &stun)))
653 0 : ABORT(r);
654 0 : stun->stun->params.allocate_request.lifetime_secs =
655 : TURN_LIFETIME_REQUEST_SECONDS;
656 :
657 0 : if (ctx->state == NR_TURN_CLIENT_STATE_INITTED) {
658 0 : if ((r=nr_turn_stun_ctx_start(stun)))
659 0 : ABORT(r);
660 0 : ctx->state = NR_TURN_CLIENT_STATE_ALLOCATING;
661 : } else {
662 0 : ABORT(R_ALREADY);
663 : }
664 :
665 0 : _status=0;
666 : abort:
667 0 : if (_status) {
668 0 : nr_turn_client_failed(ctx);
669 : }
670 :
671 0 : return(_status);
672 : }
673 :
674 0 : int nr_turn_client_process_response(nr_turn_client_ctx *ctx,
675 : UCHAR *msg, int len,
676 : nr_transport_addr *turn_server_addr)
677 : {
678 : int r, _status;
679 : nr_turn_stun_ctx *sc1;
680 :
681 0 : switch (ctx->state) {
682 : case NR_TURN_CLIENT_STATE_ALLOCATING:
683 : case NR_TURN_CLIENT_STATE_ALLOCATED:
684 0 : break;
685 : default:
686 0 : ABORT(R_FAILED);
687 : }
688 :
689 0 : sc1 = STAILQ_FIRST(&ctx->stun_ctxs);
690 0 : while (sc1) {
691 0 : r = nr_stun_client_process_response(sc1->stun, msg, len, turn_server_addr);
692 0 : if (!r)
693 0 : break;
694 0 : if (r==R_RETRY) /* Likely a 401 and we will retry */
695 0 : break;
696 0 : if (r != R_REJECTED)
697 0 : ABORT(r);
698 0 : sc1 = STAILQ_NEXT(sc1, entry);
699 : }
700 0 : if (!sc1)
701 0 : ABORT(R_REJECTED);
702 :
703 0 : _status=0;
704 : abort:
705 0 : return(_status);
706 : }
707 :
708 0 : static int nr_turn_client_refresh_setup(nr_turn_client_ctx *ctx,
709 : nr_turn_stun_ctx **sctx)
710 : {
711 0 : nr_turn_stun_ctx *stun = 0;
712 : int r,_status;
713 :
714 0 : assert(ctx->state == NR_TURN_CLIENT_STATE_ALLOCATED);
715 0 : if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
716 0 : ABORT(R_NOT_PERMITTED);
717 :
718 0 : if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_REFRESH_REQUEST,
719 : nr_turn_client_refresh_cb,
720 : nr_turn_client_error_cb,
721 : &stun)))
722 0 : ABORT(r);
723 :
724 0 : if ((r=nr_turn_stun_set_auth_params(stun, ctx->realm, ctx->nonce)))
725 0 : ABORT(r);
726 :
727 0 : stun->stun->params.refresh_request.lifetime_secs =
728 : TURN_LIFETIME_REQUEST_SECONDS;
729 :
730 :
731 0 : *sctx=stun;
732 :
733 0 : _status=0;
734 : abort:
735 0 : return(_status);
736 : }
737 :
738 0 : static int nr_turn_client_start_refresh_timer(nr_turn_client_ctx *tctx,
739 : nr_turn_stun_ctx *sctx,
740 : UINT4 lifetime)
741 : {
742 : int _status;
743 :
744 0 : assert(!tctx->refresh_timer_handle);
745 :
746 0 : if (lifetime <= TURN_REFRESH_SLACK_SECONDS) {
747 0 : r_log(NR_LOG_TURN, LOG_ERR, "Too short lifetime specified for turn %u", lifetime);
748 0 : ABORT(R_BAD_DATA);
749 : }
750 :
751 0 : if (lifetime > 3600)
752 0 : lifetime = 3600;
753 :
754 0 : lifetime -= TURN_REFRESH_SLACK_SECONDS;
755 :
756 0 : r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Setting refresh timer for %u seconds",
757 : tctx->label, lifetime);
758 0 : NR_ASYNC_TIMER_SET(lifetime * 1000, nr_turn_client_refresh_timer_cb, sctx,
759 : &tctx->refresh_timer_handle);
760 :
761 0 : _status=0;
762 : abort:
763 0 : if (_status) {
764 0 : nr_turn_client_failed(tctx);
765 : }
766 0 : return _status;
767 : }
768 :
769 0 : static void nr_turn_client_refresh_timer_cb(NR_SOCKET s, int how, void *arg)
770 : {
771 0 : nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
772 : int r,_status;
773 :
774 0 : r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Refresh timer fired",
775 0 : ctx->tctx->label);
776 :
777 0 : ctx->tctx->refresh_timer_handle=0;
778 0 : if ((r=nr_turn_stun_ctx_start(ctx))) {
779 0 : ABORT(r);
780 : }
781 :
782 0 : _status=0;
783 : abort:
784 0 : if (_status) {
785 0 : nr_turn_client_failed(ctx->tctx);
786 : }
787 0 : return;
788 : }
789 :
790 0 : static void nr_turn_client_refresh_cb(NR_SOCKET s, int how, void *arg)
791 : {
792 : int r, _status;
793 0 : nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
794 : /* Save lifetime from the reset */
795 0 : UINT4 lifetime = ctx->stun->results.refresh_response.lifetime_secs;
796 :
797 0 : r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Refresh succeeded. lifetime=%u",
798 0 : ctx->tctx->label, lifetime);
799 :
800 0 : if ((r=nr_turn_client_start_refresh_timer(
801 0 : ctx->tctx, ctx, lifetime)))
802 0 : ABORT(r);
803 :
804 0 : _status=0;
805 :
806 : abort:
807 0 : if (_status) {
808 0 : nr_turn_client_failed(ctx->tctx);
809 : }
810 0 : }
811 :
812 : /* TODO(ekr@rtfm.com): We currently don't support channels.
813 : We might in the future. Mozilla bug 857736 */
814 0 : int nr_turn_client_send_indication(nr_turn_client_ctx *ctx,
815 : const UCHAR *msg, size_t len,
816 : int flags, nr_transport_addr *remote_addr)
817 : {
818 : int r,_status;
819 0 : nr_stun_client_send_indication_params params = { { 0 } };
820 0 : nr_stun_message *ind = 0;
821 :
822 0 : if (ctx->state != NR_TURN_CLIENT_STATE_ALLOCATED)
823 0 : ABORT(R_FAILED);
824 :
825 0 : r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Send indication len=%zu",
826 : ctx->label, len);
827 :
828 0 : if ((r=nr_turn_client_ensure_perm(ctx, remote_addr)))
829 0 : ABORT(r);
830 :
831 0 : if ((r=nr_transport_addr_copy(¶ms.remote_addr, remote_addr)))
832 0 : ABORT(r);
833 :
834 0 : params.data.data = (UCHAR*)msg;
835 0 : params.data.len = len;
836 :
837 0 : if ((r=nr_stun_build_send_indication(¶ms, &ind)))
838 0 : ABORT(r);
839 :
840 0 : if ((r=nr_turn_client_send_stun_request(ctx, ind, flags)))
841 0 : ABORT(r);
842 :
843 0 : _status=0;
844 : abort:
845 0 : nr_stun_message_destroy(&ind);
846 0 : return(_status);
847 : }
848 :
849 0 : int nr_turn_client_parse_data_indication(nr_turn_client_ctx *ctx,
850 : nr_transport_addr *source_addr,
851 : UCHAR *msg, size_t len,
852 : UCHAR *newmsg, size_t *newlen,
853 : size_t newsize,
854 : nr_transport_addr *remote_addr)
855 : {
856 : int r,_status;
857 0 : nr_stun_message *ind=0;
858 : nr_stun_message_attribute *attr;
859 : nr_turn_permission *perm;
860 :
861 0 : if (nr_transport_addr_cmp(&ctx->turn_server_addr, source_addr,
862 : NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
863 0 : r_log(NR_LOG_TURN, LOG_WARNING,
864 : "TURN(%s): Indication from unexpected source addr %s (expected %s)",
865 0 : ctx->label, source_addr->as_string, ctx->turn_server_addr.as_string);
866 0 : ABORT(R_REJECTED);
867 : }
868 :
869 0 : if ((r=nr_stun_message_create2(&ind, msg, len)))
870 0 : ABORT(r);
871 0 : if ((r=nr_stun_decode_message(ind, 0, 0)))
872 0 : ABORT(r);
873 :
874 0 : if (ind->header.type != NR_STUN_MSG_DATA_INDICATION)
875 0 : ABORT(R_BAD_ARGS);
876 :
877 0 : if (!nr_stun_message_has_attribute(ind, NR_STUN_ATTR_XOR_PEER_ADDRESS, &attr))
878 0 : ABORT(R_BAD_ARGS);
879 :
880 0 : if ((r=nr_turn_permission_find(ctx, &attr->u.xor_mapped_address.unmasked,
881 : &perm))) {
882 0 : if (r == R_NOT_FOUND) {
883 0 : r_log(NR_LOG_TURN, LOG_WARNING,
884 : "TURN(%s): Indication from peer addr %s with no permission",
885 0 : ctx->label, attr->u.xor_mapped_address.unmasked.as_string);
886 : }
887 0 : ABORT(r);
888 : }
889 :
890 0 : if ((r=nr_transport_addr_copy(remote_addr,
891 0 : &attr->u.xor_mapped_address.unmasked)))
892 0 : ABORT(r);
893 :
894 : #if REFRESH_RESERVATION_ON_RECV
895 0 : if ((r=nr_turn_client_ensure_perm(ctx, remote_addr))) {
896 0 : ABORT(r);
897 : }
898 : #endif
899 :
900 0 : if (!nr_stun_message_has_attribute(ind, NR_STUN_ATTR_DATA, &attr)) {
901 0 : ABORT(R_BAD_DATA);
902 : }
903 :
904 0 : assert(newsize >= attr->u.data.length);
905 0 : if (newsize < attr->u.data.length)
906 0 : ABORT(R_BAD_ARGS);
907 :
908 0 : memcpy(newmsg, attr->u.data.data, attr->u.data.length);
909 0 : *newlen = attr->u.data.length;
910 :
911 0 : _status=0;
912 : abort:
913 0 : nr_stun_message_destroy(&ind);
914 0 : return(_status);
915 : }
916 :
917 :
918 :
919 : /* The permissions model is as follows:
920 :
921 : - We keep a list of all the permissions we have ever requested
922 : along with when they were last established.
923 : - Whenever someone sends a packet, we automatically create/
924 : refresh the permission.
925 :
926 : This means that permissions automatically time out if
927 : unused.
928 :
929 : */
930 0 : int nr_turn_client_ensure_perm(nr_turn_client_ctx *ctx, nr_transport_addr *addr)
931 : {
932 : int r, _status;
933 0 : nr_turn_permission *perm = 0;
934 : UINT8 now;
935 0 : UINT8 turn_permission_refresh = (TURN_PERMISSION_LIFETIME_SECONDS -
936 : TURN_REFRESH_SLACK_SECONDS) * TURN_USECS_PER_S;
937 :
938 0 : if ((r=nr_turn_permission_find(ctx, addr, &perm))) {
939 0 : if (r == R_NOT_FOUND) {
940 0 : if ((r=nr_turn_permission_create(ctx, addr, &perm)))
941 0 : ABORT(r);
942 : }
943 : else {
944 0 : ABORT(r);
945 : }
946 : }
947 :
948 0 : assert(perm);
949 :
950 : /* Now check that the permission is up-to-date */
951 0 : now = r_gettimeint();
952 :
953 0 : if ((now - perm->last_used) > turn_permission_refresh) {
954 0 : r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Permission for %s requires refresh",
955 0 : ctx->label, perm->addr.as_string);
956 :
957 0 : if ((r=nr_turn_stun_ctx_start(perm->stun)))
958 0 : ABORT(r);
959 :
960 0 : perm->last_used = now; /* Update the time now so we don't retry on
961 : next packet */
962 : }
963 :
964 0 : _status=0;
965 : abort:
966 0 : return(_status);
967 : }
968 :
969 0 : static int nr_turn_permission_create(nr_turn_client_ctx *ctx, nr_transport_addr *addr,
970 : nr_turn_permission **permp)
971 : {
972 : int r, _status;
973 0 : nr_turn_permission *perm = 0;
974 :
975 0 : assert(ctx->state == NR_TURN_CLIENT_STATE_ALLOCATED);
976 :
977 0 : r_log(NR_LOG_TURN, LOG_INFO, "TURN(%s): Creating permission for %s",
978 0 : ctx->label, addr->as_string);
979 :
980 0 : if (!(perm = RCALLOC(sizeof(nr_turn_permission))))
981 0 : ABORT(R_NO_MEMORY);
982 :
983 0 : if ((r=nr_transport_addr_copy(&perm->addr, addr)))
984 0 : ABORT(r);
985 :
986 0 : perm->last_used = 0;
987 :
988 0 : if ((r=nr_turn_stun_ctx_create(ctx, NR_TURN_CLIENT_MODE_PERMISSION_REQUEST,
989 : nr_turn_client_permissions_cb,
990 : nr_turn_client_permission_error_cb,
991 0 : &perm->stun)))
992 0 : ABORT(r);
993 :
994 : /* We want to authenticate on the first packet */
995 0 : if ((r=nr_turn_stun_set_auth_params(perm->stun, ctx->realm, ctx->nonce)))
996 0 : ABORT(r);
997 :
998 0 : if ((r=nr_transport_addr_copy(
999 0 : &perm->stun->stun->params.permission_request.remote_addr, addr)))
1000 0 : ABORT(r);
1001 0 : STAILQ_INSERT_TAIL(&ctx->permissions, perm, entry);
1002 :
1003 0 : *permp = perm;
1004 :
1005 0 : _status=0;
1006 : abort:
1007 0 : if (_status) {
1008 0 : nr_turn_permission_destroy(&perm);
1009 : }
1010 0 : return(_status);
1011 : }
1012 :
1013 :
1014 0 : static int nr_turn_permission_find(nr_turn_client_ctx *ctx, nr_transport_addr *addr,
1015 : nr_turn_permission **permp)
1016 : {
1017 : nr_turn_permission *perm;
1018 : int _status;
1019 :
1020 0 : perm = STAILQ_FIRST(&ctx->permissions);
1021 0 : while (perm) {
1022 0 : if (!nr_transport_addr_cmp(&perm->addr, addr,
1023 : NR_TRANSPORT_ADDR_CMP_MODE_ADDR))
1024 0 : break;
1025 :
1026 0 : perm = STAILQ_NEXT(perm, entry);
1027 : }
1028 :
1029 0 : if (!perm) {
1030 0 : ABORT(R_NOT_FOUND);
1031 : }
1032 0 : if (perm->stun->last_error_code == 403) {
1033 0 : ABORT(R_NOT_PERMITTED);
1034 : }
1035 0 : *permp = perm;
1036 :
1037 0 : _status=0;
1038 : abort:
1039 0 : return(_status);
1040 : }
1041 :
1042 0 : static void nr_turn_client_permissions_cb(NR_SOCKET s, int how, void *arg)
1043 : {
1044 0 : nr_turn_stun_ctx *ctx = (nr_turn_stun_ctx *)arg;
1045 0 : r_log(NR_LOG_TURN, LOG_DEBUG, "TURN(%s): Successfully refreshed permission",
1046 0 : ctx->tctx->label);
1047 0 : }
1048 :
1049 : /* Note that we don't destroy the nr_turn_stun_ctx. That is owned by the
1050 : nr_turn_client_ctx. */
1051 0 : static int nr_turn_permission_destroy(nr_turn_permission **permp)
1052 : {
1053 : nr_turn_permission *perm;
1054 :
1055 0 : if (!permp || !*permp)
1056 0 : return(0);
1057 :
1058 0 : perm = *permp;
1059 0 : *permp = 0;
1060 :
1061 0 : RFREE(perm);
1062 :
1063 0 : return(0);
1064 : }
1065 :
1066 : #endif /* USE_TURN */
|