Source code

Revision control

Other Tools

1
/*
2
Copyright (c) 2007, Adobe Systems, Incorporated
3
All rights reserved.
4
5
Redistribution and use in source and binary forms, with or without
6
modification, are permitted provided that the following conditions are
7
met:
8
9
* Redistributions of source code must retain the above copyright
10
notice, this list of conditions and the following disclaimer.
11
12
* Redistributions in binary form must reproduce the above copyright
13
notice, this list of conditions and the following disclaimer in the
14
documentation and/or other materials provided with the distribution.
15
16
* Neither the name of Adobe Systems, Network Resonance nor the names of its
17
contributors may be used to endorse or promote products derived from
18
this software without specific prior written permission.
19
20
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
*/
32
33
#include <assert.h>
34
#include <string.h>
35
#include <math.h>
36
37
#include <nr_api.h>
38
#include "stun.h"
39
#include "async_timer.h"
40
#include "registry.h"
41
#include "stun_reg.h"
42
#include "nr_crypto.h"
43
#include "r_time.h"
44
45
static int nr_stun_client_send_request(nr_stun_client_ctx *ctx);
46
static void nr_stun_client_timer_expired_cb(NR_SOCKET s, int b, void *cb_arg);
47
static int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password);
48
49
#define NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD 1
50
#define NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK 2
51
52
int nr_stun_client_ctx_create(char *label, nr_socket *sock, nr_transport_addr *peer, UINT4 RTO, nr_stun_client_ctx **ctxp)
53
{
54
nr_stun_client_ctx *ctx=0;
55
char allow_loopback;
56
int r,_status;
57
58
if ((r=nr_stun_startup()))
59
ABORT(r);
60
61
if(!(ctx=RCALLOC(sizeof(nr_stun_client_ctx))))
62
ABORT(R_NO_MEMORY);
63
64
ctx->state=NR_STUN_CLIENT_STATE_INITTED;
65
66
if(!(ctx->label=r_strdup(label)))
67
ABORT(R_NO_MEMORY);
68
69
ctx->sock=sock;
70
71
nr_socket_getaddr(sock,&ctx->my_addr);
72
nr_transport_addr_copy(&ctx->peer_addr,peer);
73
74
if (RTO != 0) {
75
ctx->rto_ms = RTO;
76
} else if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_RETRANSMIT_TIMEOUT, &ctx->rto_ms)) {
77
ctx->rto_ms = 100;
78
}
79
80
if (NR_reg_get_double(NR_STUN_REG_PREF_CLNT_RETRANSMIT_BACKOFF, &ctx->retransmission_backoff_factor))
81
ctx->retransmission_backoff_factor = 2.0;
82
83
if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_MAXIMUM_TRANSMITS, &ctx->maximum_transmits))
84
ctx->maximum_transmits = 7;
85
86
if (NR_reg_get_uint4(NR_STUN_REG_PREF_CLNT_FINAL_RETRANSMIT_BACKOFF, &ctx->maximum_transmits_timeout_ms))
87
ctx->maximum_transmits_timeout_ms = 16 * ctx->rto_ms;
88
89
ctx->mapped_addr_check_mask = NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD;
90
if (NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, &allow_loopback) ||
91
!allow_loopback) {
92
ctx->mapped_addr_check_mask |= NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK;
93
}
94
95
if (ctx->my_addr.protocol == IPPROTO_TCP) {
96
/* Because TCP is reliable there is only one final timeout value.
97
* We store the timeout value for TCP in here, because timeout_ms gets
98
* reset to 0 in client_reset() which gets called from client_start() */
99
ctx->maximum_transmits_timeout_ms = ctx->rto_ms *
100
pow(ctx->retransmission_backoff_factor,
101
ctx->maximum_transmits);
102
ctx->maximum_transmits = 1;
103
}
104
105
*ctxp=ctx;
106
107
_status=0;
108
abort:
109
if(_status){
110
nr_stun_client_ctx_destroy(&ctx);
111
}
112
return(_status);
113
}
114
115
static void nr_stun_client_fire_finished_cb(nr_stun_client_ctx *ctx)
116
{
117
if (ctx->finished_cb) {
118
NR_async_cb finished_cb = ctx->finished_cb;
119
ctx->finished_cb = 0; /* prevent 2nd call */
120
/* finished_cb call must be absolutely last thing in function
121
* because as a side effect this ctx may be operated on in the
122
* callback */
123
finished_cb(0,0,ctx->cb_arg);
124
}
125
}
126
127
int nr_stun_client_start(nr_stun_client_ctx *ctx, int mode, NR_async_cb finished_cb, void *cb_arg)
128
{
129
int r,_status;
130
131
if (ctx->state != NR_STUN_CLIENT_STATE_INITTED)
132
ABORT(R_NOT_PERMITTED);
133
134
ctx->mode=mode;
135
136
ctx->state=NR_STUN_CLIENT_STATE_RUNNING;
137
ctx->finished_cb=finished_cb;
138
ctx->cb_arg=cb_arg;
139
140
if(mode!=NR_STUN_CLIENT_MODE_KEEPALIVE){
141
if(r=nr_stun_client_send_request(ctx))
142
ABORT(r);
143
}
144
145
_status=0;
146
abort:
147
if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) {
148
nr_stun_client_fire_finished_cb(ctx);
149
}
150
151
return(_status);
152
}
153
154
int nr_stun_client_restart(nr_stun_client_ctx *ctx)
155
{
156
int r,_status;
157
int mode;
158
NR_async_cb finished_cb;
159
void *cb_arg;
160
nr_stun_message_attribute *ec;
161
nr_stun_message_attribute *as;
162
163
if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
164
ABORT(R_NOT_PERMITTED);
165
166
assert(ctx->retry_ct <= 2);
167
if (ctx->retry_ct > 2)
168
ABORT(R_NOT_PERMITTED);
169
170
++ctx->retry_ct;
171
172
mode = ctx->mode;
173
finished_cb = ctx->finished_cb;
174
cb_arg = ctx->cb_arg;
175
176
if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_ERROR_CODE, &ec)
177
&& ec->u.error_code.number == 300) {
178
if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_ALTERNATE_SERVER, &as)) {
179
nr_transport_addr_copy(&ctx->peer_addr, &as->u.alternate_server);
180
}
181
}
182
183
nr_stun_client_reset(ctx);
184
185
if (r=nr_stun_client_start(ctx, mode, finished_cb, cb_arg))
186
ABORT(r);
187
188
_status=0;
189
abort:
190
return(_status);
191
}
192
193
int
194
nr_stun_client_reset(nr_stun_client_ctx *ctx)
195
{
196
/* Cancel the timer firing */
197
if (ctx->timer_handle){
198
NR_async_timer_cancel(ctx->timer_handle);
199
ctx->timer_handle=0;
200
}
201
202
nr_stun_message_destroy(&ctx->request);
203
ctx->request = 0;
204
205
nr_stun_message_destroy(&ctx->response);
206
ctx->response = 0;
207
208
memset(&ctx->results, 0, sizeof(ctx->results));
209
210
ctx->mode = 0;
211
ctx->finished_cb = 0;
212
ctx->cb_arg = 0;
213
ctx->request_ct = 0;
214
ctx->timeout_ms = 0;
215
216
ctx->state = NR_STUN_CLIENT_STATE_INITTED;
217
218
return 0;
219
}
220
221
static void nr_stun_client_timer_expired_cb(NR_SOCKET s, int b, void *cb_arg)
222
{
223
int _status;
224
nr_stun_client_ctx *ctx=cb_arg;
225
struct timeval now;
226
INT8 ms_waited;
227
228
/* Prevent this timer from being cancelled later */
229
ctx->timer_handle=0;
230
231
/* Shouldn't happen */
232
if(ctx->state==NR_STUN_CLIENT_STATE_CANCELLED)
233
ABORT(R_REJECTED);
234
235
gettimeofday(&now, 0);
236
if (r_timeval_diff_ms(&now, &ctx->timer_set, &ms_waited)) {
237
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timer expired",ctx->label);
238
}
239
else {
240
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timer expired (after %llu ms)",ctx->label, ms_waited);
241
}
242
243
if (ctx->request_ct >= ctx->maximum_transmits) {
244
r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): Timed out",ctx->label);
245
ctx->state=NR_STUN_CLIENT_STATE_TIMED_OUT;
246
ABORT(R_FAILED);
247
}
248
249
if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
250
ABORT(R_NOT_PERMITTED);
251
252
// track retransmits for ice telemetry
253
nr_accumulate_count(&(ctx->retransmit_ct), 1);
254
255
/* as a side effect will reset the timer */
256
nr_stun_client_send_request(ctx);
257
258
_status = 0;
259
abort:
260
if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING) {
261
/* Cancel the timer firing */
262
if (ctx->timer_handle){
263
NR_async_timer_cancel(ctx->timer_handle);
264
ctx->timer_handle=0;
265
}
266
267
nr_stun_client_fire_finished_cb(ctx);
268
}
269
if (_status) {
270
// cb doesn't return anything, but we should probably log that we aborted
271
// This also quiets the unused variable warnings.
272
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Timer expired cb abort with status: %d",
273
ctx->label, _status);
274
}
275
return;
276
}
277
278
int nr_stun_client_force_retransmit(nr_stun_client_ctx *ctx)
279
{
280
int r,_status;
281
282
if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
283
ABORT(R_NOT_PERMITTED);
284
285
if (ctx->request_ct > ctx->maximum_transmits) {
286
r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): Too many retransmit attempts",ctx->label);
287
ABORT(R_FAILED);
288
}
289
290
/* if there is a scheduled retransimt, get rid of the scheduled retransmit
291
* and retransmit immediately */
292
if (ctx->timer_handle) {
293
NR_async_timer_cancel(ctx->timer_handle);
294
ctx->timer_handle=0;
295
296
if (r=nr_stun_client_send_request(ctx))
297
ABORT(r);
298
}
299
300
_status=0;
301
abort:
302
303
return(_status);
304
}
305
306
static int nr_stun_client_send_request(nr_stun_client_ctx *ctx)
307
{
308
int r,_status;
309
char string[256];
310
311
if (ctx->state != NR_STUN_CLIENT_STATE_RUNNING)
312
ABORT(R_NOT_PERMITTED);
313
314
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Sending check request (my_addr=%s,peer_addr=%s)",ctx->label,ctx->my_addr.as_string,ctx->peer_addr.as_string);
315
316
if (ctx->request == 0) {
317
switch (ctx->mode) {
318
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
319
ctx->params.stun_binding_request.nonce = ctx->nonce;
320
ctx->params.stun_binding_request.realm = ctx->realm;
321
assert(0);
322
ABORT(R_INTERNAL);
323
/* TODO(ekr@rtfm.com): Need to implement long-term auth for binding
324
requests */
325
if ((r=nr_stun_build_req_lt_auth(&ctx->params.stun_binding_request, &ctx->request)))
326
ABORT(r);
327
break;
328
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
329
if ((r=nr_stun_build_req_st_auth(&ctx->params.stun_binding_request, &ctx->request)))
330
ABORT(r);
331
break;
332
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
333
if ((r=nr_stun_build_req_no_auth(&ctx->params.stun_binding_request, &ctx->request)))
334
ABORT(r);
335
break;
336
case NR_STUN_CLIENT_MODE_KEEPALIVE:
337
if ((r=nr_stun_build_keepalive(&ctx->params.stun_keepalive, &ctx->request)))
338
ABORT(r);
339
break;
340
#ifdef USE_STUND_0_96
341
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
342
if ((r=nr_stun_build_req_stund_0_96(&ctx->params.stun_binding_request_stund_0_96, &ctx->request)))
343
ABORT(r);
344
break;
345
#endif /* USE_STUND_0_96 */
346
347
#ifdef USE_ICE
348
case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
349
if ((r=nr_stun_build_use_candidate(&ctx->params.ice_binding_request, &ctx->request)))
350
ABORT(r);
351
break;
352
case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
353
if ((r=nr_stun_build_req_ice(&ctx->params.ice_binding_request, &ctx->request)))
354
ABORT(r);
355
break;
356
#endif /* USE_ICE */
357
358
#ifdef USE_TURN
359
case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST:
360
if ((r=nr_stun_build_allocate_request(&ctx->auth_params, &ctx->params.allocate_request, &ctx->request)))
361
ABORT(r);
362
break;
363
case NR_TURN_CLIENT_MODE_REFRESH_REQUEST:
364
if ((r=nr_stun_build_refresh_request(&ctx->auth_params, &ctx->params.refresh_request, &ctx->request)))
365
ABORT(r);
366
break;
367
case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST:
368
if ((r=nr_stun_build_permission_request(&ctx->auth_params, &ctx->params.permission_request, &ctx->request)))
369
ABORT(r);
370
break;
371
case NR_TURN_CLIENT_MODE_SEND_INDICATION:
372
if ((r=nr_stun_build_send_indication(&ctx->params.send_indication, &ctx->request)))
373
ABORT(r);
374
break;
375
#endif /* USE_TURN */
376
377
default:
378
assert(0);
379
ABORT(R_FAILED);
380
break;
381
}
382
}
383
384
if (ctx->request->length == 0) {
385
if ((r=nr_stun_encode_message(ctx->request)))
386
ABORT(r);
387
}
388
389
snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Sending to %s ", ctx->label, ctx->peer_addr.as_string);
390
r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)ctx->request->buffer, ctx->request->length);
391
392
assert(ctx->my_addr.protocol==ctx->peer_addr.protocol);
393
394
if(r=nr_socket_sendto(ctx->sock, ctx->request->buffer, ctx->request->length, 0, &ctx->peer_addr)) {
395
if (r != R_WOULDBLOCK) {
396
ABORT(r);
397
}
398
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_socket_sendto blocked, treating as dropped packet",ctx->label);
399
}
400
401
ctx->request_ct++;
402
403
if (NR_STUN_GET_TYPE_CLASS(ctx->request->header.type) == NR_CLASS_INDICATION) {
404
/* no need to set the timer because indications don't receive a
405
* response */
406
}
407
else {
408
if (ctx->request_ct >= ctx->maximum_transmits) {
409
/* Reliable transport only get here once. Unreliable get here for
410
* their final timeout. */
411
ctx->timeout_ms += ctx->maximum_transmits_timeout_ms;
412
}
413
else if (ctx->timeout_ms) {
414
/* exponential backoff */
415
ctx->timeout_ms *= ctx->retransmission_backoff_factor;
416
}
417
else {
418
/* initial timeout unreliable transports */
419
ctx->timeout_ms = ctx->rto_ms;
420
}
421
422
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Next timer will fire in %u ms",ctx->label, ctx->timeout_ms);
423
424
gettimeofday(&ctx->timer_set, 0);
425
426
assert(ctx->timeout_ms);
427
NR_ASYNC_TIMER_SET(ctx->timeout_ms, nr_stun_client_timer_expired_cb, ctx, &ctx->timer_handle);
428
}
429
430
_status=0;
431
abort:
432
if (_status) {
433
nr_stun_client_failed(ctx);
434
}
435
return(_status);
436
}
437
438
static int nr_stun_client_get_password(void *arg, nr_stun_message *msg, Data **password)
439
{
440
*password = (Data*)arg;
441
if (!arg)
442
return(R_NOT_FOUND);
443
return(0);
444
}
445
446
int nr_stun_transport_addr_check(nr_transport_addr* addr, UINT4 check)
447
{
448
if((check & NR_STUN_TRANSPORT_ADDR_CHECK_WILDCARD) && nr_transport_addr_is_wildcard(addr))
449
return(R_BAD_DATA);
450
451
if ((check & NR_STUN_TRANSPORT_ADDR_CHECK_LOOPBACK) && nr_transport_addr_is_loopback(addr))
452
return(R_BAD_DATA);
453
454
return(0);
455
}
456
457
int nr_stun_client_process_response(nr_stun_client_ctx *ctx, UCHAR *msg, int len, nr_transport_addr *peer_addr)
458
{
459
int r,_status;
460
char string[256];
461
char *username = 0;
462
Data *password = 0;
463
nr_stun_message_attribute *attr;
464
nr_transport_addr *mapped_addr = 0;
465
int fail_on_error = 0;
466
UCHAR hmac_key_d[16];
467
Data hmac_key;
468
int compute_lt_key=0;
469
/* TODO(bcampen@mozilla.com): Bug 1023619, refactor this. */
470
int response_matched=0;
471
472
ATTACH_DATA(hmac_key, hmac_key_d);
473
474
if ((ctx->state != NR_STUN_CLIENT_STATE_RUNNING) &&
475
(ctx->state != NR_STUN_CLIENT_STATE_WAITING))
476
ABORT(R_REJECTED);
477
478
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Inspecting STUN response (my_addr=%s, peer_addr=%s)",ctx->label,ctx->my_addr.as_string,peer_addr->as_string);
479
480
snprintf(string, sizeof(string)-1, "STUN-CLIENT(%s): Received ", ctx->label);
481
r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)msg, len);
482
483
/* determine password */
484
switch (ctx->mode) {
485
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
486
compute_lt_key = 1;
487
/* Fall through */
488
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
489
password = ctx->params.stun_binding_request.password;
490
break;
491
492
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
493
/* do nothing */
494
break;
495
496
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
497
/* do nothing */
498
break;
499
500
#ifdef USE_ICE
501
case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
502
password = &ctx->params.ice_binding_request.password;
503
break;
504
case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
505
password = &ctx->params.ice_binding_request.password;
506
break;
507
#endif /* USE_ICE */
508
509
#ifdef USE_TURN
510
case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST:
511
fail_on_error = 1;
512
compute_lt_key = 1;
513
username = ctx->auth_params.username;
514
password = &ctx->auth_params.password;
515
/* do nothing */
516
break;
517
case NR_TURN_CLIENT_MODE_REFRESH_REQUEST:
518
fail_on_error = 1;
519
compute_lt_key = 1;
520
username = ctx->auth_params.username;
521
password = &ctx->auth_params.password;
522
/* do nothing */
523
break;
524
case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST:
525
fail_on_error = 1;
526
compute_lt_key = 1;
527
username = ctx->auth_params.username;
528
password = &ctx->auth_params.password;
529
/* do nothing */
530
break;
531
case NR_TURN_CLIENT_MODE_SEND_INDICATION:
532
/* do nothing -- we just got our DATA-INDICATION */
533
break;
534
#endif /* USE_TURN */
535
536
default:
537
assert(0);
538
ABORT(R_FAILED);
539
break;
540
}
541
542
if (compute_lt_key) {
543
if (!ctx->realm || !username) {
544
r_log(NR_LOG_STUN, LOG_DEBUG, "Long-term auth required but no realm/username specified. Randomizing key");
545
/* Fill the key with random bytes to guarantee non-match */
546
if (r=nr_crypto_random_bytes(hmac_key_d, sizeof(hmac_key_d)))
547
ABORT(r);
548
}
549
else {
550
if (r=nr_stun_compute_lt_message_integrity_password(username, ctx->realm,
551
password, &hmac_key))
552
ABORT(r);
553
}
554
password = &hmac_key;
555
}
556
557
if (ctx->response) {
558
nr_stun_message_destroy(&ctx->response);
559
}
560
561
/* TODO(bcampen@mozilla.com): Bug 1023619, refactor this. */
562
if ((r=nr_stun_message_create2(&ctx->response, msg, len)))
563
ABORT(r);
564
565
if ((r=nr_stun_decode_message(ctx->response, nr_stun_client_get_password, password))) {
566
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): error decoding response",ctx->label);
567
ABORT(r);
568
}
569
570
/* This will return an error if request and response don't match,
571
which is how we reject responses that match other contexts. */
572
if ((r=nr_stun_receive_message(ctx->request, ctx->response))) {
573
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Response is not for us",ctx->label);
574
ABORT(r);
575
}
576
577
r_log(NR_LOG_STUN,LOG_INFO,
578
"STUN-CLIENT(%s): Received response; processing",ctx->label);
579
response_matched=1;
580
581
/* TODO: !nn! currently using password!=0 to mean that auth is required,
582
* TODO: !nn! but we should probably pass that in explicitly via the
583
* TODO: !nn! usage (ctx->mode?) */
584
if (password) {
585
if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_NONCE, 0)) {
586
if ((r=nr_stun_receive_response_long_term_auth(ctx->response, ctx)))
587
ABORT(r);
588
}
589
else {
590
if ((r=nr_stun_receive_response_short_term_auth(ctx->response)))
591
ABORT(r);
592
}
593
}
594
595
if (NR_STUN_GET_TYPE_CLASS(ctx->response->header.type) == NR_CLASS_RESPONSE) {
596
if ((r=nr_stun_process_success_response(ctx->response)))
597
ABORT(r);
598
}
599
else {
600
if (fail_on_error) {
601
ctx->state = NR_STUN_CLIENT_STATE_FAILED;
602
}
603
/* Note: most times we call process_error_response, we get r != 0.
604
605
However, if the error is to be discarded, we get r == 0, smash
606
the error code, and just keep going.
607
*/
608
if ((r=nr_stun_process_error_response(ctx->response, &ctx->error_code))) {
609
ABORT(r);
610
}
611
else {
612
ctx->error_code = 0xffff;
613
/* drop the error on the floor */
614
ABORT(R_FAILED);
615
}
616
}
617
618
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Successfully parsed mode=%d",ctx->label,ctx->mode);
619
620
/* TODO: !nn! this should be moved to individual message receive/processing sections */
621
switch (ctx->mode) {
622
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
623
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
624
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
625
ABORT(R_BAD_DATA);
626
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
627
ABORT(R_BAD_DATA);
628
629
mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
630
break;
631
632
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
633
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
634
if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, 0)) {
635
/* Compensate for a bug in Google's STUN servers where they always respond with MAPPED-ADDRESS */
636
r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS but MAPPED-ADDRESS. Falling back (though server is wrong).", ctx->label);
637
}
638
else {
639
ABORT(R_BAD_DATA);
640
}
641
}
642
643
mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
644
break;
645
646
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
647
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, 0) && ! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
648
ABORT(R_BAD_DATA);
649
650
mapped_addr = &ctx->results.stun_binding_response_stund_0_96.mapped_addr;
651
break;
652
653
#ifdef USE_ICE
654
case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
655
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
656
ABORT(R_BAD_DATA);
657
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
658
ABORT(R_BAD_DATA);
659
660
mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
661
break;
662
case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
663
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
664
ABORT(R_BAD_DATA);
665
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
666
ABORT(R_BAD_DATA);
667
668
mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
669
break;
670
#endif /* USE_ICE */
671
672
#ifdef USE_TURN
673
case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST:
674
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0))
675
ABORT(R_BAD_DATA);
676
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
677
ABORT(R_BAD_DATA);
678
679
if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_RELAY_ADDRESS, &attr))
680
ABORT(R_BAD_DATA);
681
682
if ((r=nr_stun_transport_addr_check(&attr->u.relay_address.unmasked,
683
ctx->mapped_addr_check_mask)))
684
ABORT(r);
685
686
if ((r=nr_transport_addr_copy(
687
&ctx->results.allocate_response.relay_addr,
688
&attr->u.relay_address.unmasked)))
689
ABORT(r);
690
691
if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_LIFETIME, &attr))
692
ABORT(R_BAD_DATA);
693
ctx->results.allocate_response.lifetime_secs=attr->u.lifetime_secs;
694
695
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received relay address: %s", ctx->label, ctx->results.allocate_response.relay_addr.as_string);
696
697
mapped_addr = &ctx->results.allocate_response.mapped_addr;
698
699
break;
700
case NR_TURN_CLIENT_MODE_REFRESH_REQUEST:
701
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
702
ABORT(R_BAD_DATA);
703
if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_LIFETIME, &attr))
704
ABORT(R_BAD_DATA);
705
ctx->results.refresh_response.lifetime_secs=attr->u.lifetime_secs;
706
break;
707
case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST:
708
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0))
709
ABORT(R_BAD_DATA);
710
break;
711
#endif /* USE_TURN */
712
713
default:
714
assert(0);
715
ABORT(R_FAILED);
716
break;
717
}
718
719
/* make sure we have the most up-to-date address from this peer */
720
if (nr_transport_addr_cmp(&ctx->peer_addr, peer_addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
721
r_log(NR_LOG_STUN,LOG_INFO,"STUN-CLIENT(%s): Peer moved from %s to %s", ctx->label, ctx->peer_addr.as_string, peer_addr->as_string);
722
nr_transport_addr_copy(&ctx->peer_addr, peer_addr);
723
}
724
725
if (mapped_addr) {
726
if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, &attr)) {
727
if ((r=nr_stun_transport_addr_check(&attr->u.xor_mapped_address.unmasked,
728
ctx->mapped_addr_check_mask)))
729
ABORT(r);
730
731
if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.xor_mapped_address.unmasked)))
732
ABORT(r);
733
}
734
else if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, &attr)) {
735
if ((r=nr_stun_transport_addr_check(&attr->u.mapped_address,
736
ctx->mapped_addr_check_mask)))
737
ABORT(r);
738
739
if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.mapped_address)))
740
ABORT(r);
741
}
742
else
743
ABORT(R_BAD_DATA);
744
745
// STUN doesn't distinguish protocol in mapped address, therefore
746
// assign used protocol from peer_addr
747
if (mapped_addr->protocol!=peer_addr->protocol){
748
mapped_addr->protocol=peer_addr->protocol;
749
nr_transport_addr_fmt_addr_string(mapped_addr);
750
}
751
752
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received mapped address: %s", ctx->label, mapped_addr->as_string);
753
}
754
755
ctx->state=NR_STUN_CLIENT_STATE_DONE;
756
757
_status=0;
758
abort:
759
if(_status && response_matched){
760
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): Error processing response: %s, stun error code %d.", ctx->label, nr_strerror(_status), (int)ctx->error_code);
761
}
762
763
if ((ctx->state != NR_STUN_CLIENT_STATE_RUNNING) &&
764
(ctx->state != NR_STUN_CLIENT_STATE_WAITING)) {
765
/* Cancel the timer firing */
766
if (ctx->timer_handle) {
767
NR_async_timer_cancel(ctx->timer_handle);
768
ctx->timer_handle = 0;
769
}
770
771
nr_stun_client_fire_finished_cb(ctx);
772
}
773
774
return(_status);
775
}
776
777
int nr_stun_client_ctx_destroy(nr_stun_client_ctx **ctxp)
778
{
779
nr_stun_client_ctx *ctx;
780
781
if(!ctxp || !*ctxp)
782
return(0);
783
784
ctx=*ctxp;
785
*ctxp=0;
786
787
nr_stun_client_reset(ctx);
788
789
RFREE(ctx->nonce);
790
RFREE(ctx->realm);
791
792
RFREE(ctx->label);
793
RFREE(ctx);
794
795
return(0);
796
}
797
798
799
int nr_stun_client_cancel(nr_stun_client_ctx *ctx)
800
{
801
/* Cancel the timer firing */
802
if (ctx->timer_handle){
803
NR_async_timer_cancel(ctx->timer_handle);
804
ctx->timer_handle=0;
805
}
806
807
/* Mark cancelled so we ignore any returned messsages */
808
ctx->state=NR_STUN_CLIENT_STATE_CANCELLED;
809
return(0);
810
}
811
812
int nr_stun_client_wait(nr_stun_client_ctx *ctx)
813
{
814
nr_stun_client_cancel(ctx);
815
ctx->state=NR_STUN_CLIENT_STATE_WAITING;
816
817
ctx->request_ct = ctx->maximum_transmits;
818
ctx->timeout_ms = ctx->maximum_transmits_timeout_ms;
819
NR_ASYNC_TIMER_SET(ctx->timeout_ms, nr_stun_client_timer_expired_cb, ctx, &ctx->timer_handle);
820
821
return(0);
822
}
823
824
int nr_stun_client_failed(nr_stun_client_ctx *ctx)
825
{
826
nr_stun_client_cancel(ctx);
827
ctx->state=NR_STUN_CLIENT_STATE_FAILED;
828
nr_stun_client_fire_finished_cb(ctx);
829
return(0);
830
}