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
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): long term auth failed",ctx->label);
588
ABORT(r);
589
}
590
}
591
else {
592
if ((r=nr_stun_receive_response_short_term_auth(ctx->response))) {
593
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): short term auth failed",ctx->label);
594
ABORT(r);
595
}
596
}
597
}
598
599
if (NR_STUN_GET_TYPE_CLASS(ctx->response->header.type) == NR_CLASS_RESPONSE) {
600
if ((r=nr_stun_process_success_response(ctx->response))) {
601
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_stun_process_success_response failed",ctx->label);
602
ABORT(r);
603
}
604
}
605
else {
606
if (fail_on_error) {
607
ctx->state = NR_STUN_CLIENT_STATE_FAILED;
608
}
609
/* Note: most times we call process_error_response, we get r != 0.
610
611
However, if the error is to be discarded, we get r == 0, smash
612
the error code, and just keep going.
613
*/
614
if ((r=nr_stun_process_error_response(ctx->response, &ctx->error_code))) {
615
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_stun_process_error_response failed",ctx->label);
616
ABORT(r);
617
}
618
else {
619
ctx->error_code = 0xffff;
620
/* drop the error on the floor */
621
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): processed error response",ctx->label);
622
ABORT(R_FAILED);
623
}
624
}
625
626
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Successfully parsed mode=%d",ctx->label,ctx->mode);
627
628
/* TODO: !nn! this should be moved to individual message receive/processing sections */
629
switch (ctx->mode) {
630
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_LONG_TERM_AUTH:
631
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_SHORT_TERM_AUTH:
632
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
633
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS",ctx->label);
634
ABORT(R_BAD_DATA);
635
}
636
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
637
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
638
ABORT(R_BAD_DATA);
639
}
640
641
mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
642
break;
643
644
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH:
645
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
646
if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, 0)) {
647
/* Compensate for a bug in Google's STUN servers where they always respond with MAPPED-ADDRESS */
648
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);
649
}
650
else {
651
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS or MAPPED-ADDRESS",ctx->label);
652
ABORT(R_BAD_DATA);
653
}
654
}
655
656
mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
657
break;
658
659
case NR_STUN_CLIENT_MODE_BINDING_REQUEST_STUND_0_96:
660
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)) {
661
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MAPPED-ADDRESS",ctx->label);
662
ABORT(R_BAD_DATA);
663
}
664
665
mapped_addr = &ctx->results.stun_binding_response_stund_0_96.mapped_addr;
666
break;
667
668
#ifdef USE_ICE
669
case NR_ICE_CLIENT_MODE_BINDING_REQUEST:
670
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
671
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS",ctx->label);
672
ABORT(R_BAD_DATA);
673
}
674
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
675
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
676
ABORT(R_BAD_DATA);
677
}
678
679
mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
680
break;
681
case NR_ICE_CLIENT_MODE_USE_CANDIDATE:
682
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
683
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS",ctx->label);
684
ABORT(R_BAD_DATA);
685
}
686
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
687
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
688
ABORT(R_BAD_DATA);
689
}
690
691
mapped_addr = &ctx->results.stun_binding_response.mapped_addr;
692
break;
693
#endif /* USE_ICE */
694
695
#ifdef USE_TURN
696
case NR_TURN_CLIENT_MODE_ALLOCATE_REQUEST:
697
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0)) {
698
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-MAPPED-ADDRESS",ctx->label);
699
ABORT(R_BAD_DATA);
700
}
701
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
702
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
703
ABORT(R_BAD_DATA);
704
}
705
706
if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_RELAY_ADDRESS, &attr)) {
707
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No XOR-RELAYED-ADDRESS",ctx->label);
708
ABORT(R_BAD_DATA);
709
}
710
711
if ((r=nr_stun_transport_addr_check(&attr->u.relay_address.unmasked,
712
ctx->mapped_addr_check_mask))) {
713
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_stun_transport_addr_check failed",ctx->label);
714
ABORT(r);
715
}
716
717
if ((r=nr_transport_addr_copy(
718
&ctx->results.allocate_response.relay_addr,
719
&attr->u.relay_address.unmasked))) {
720
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_transport_addr_copy failed",ctx->label);
721
ABORT(r);
722
}
723
724
if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_LIFETIME, &attr)) {
725
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No LIFETIME",ctx->label);
726
ABORT(R_BAD_DATA);
727
}
728
ctx->results.allocate_response.lifetime_secs=attr->u.lifetime_secs;
729
730
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received relay address: %s", ctx->label, ctx->results.allocate_response.relay_addr.as_string);
731
732
mapped_addr = &ctx->results.allocate_response.mapped_addr;
733
734
break;
735
case NR_TURN_CLIENT_MODE_REFRESH_REQUEST:
736
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
737
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
738
ABORT(R_BAD_DATA);
739
}
740
if (!nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_LIFETIME, &attr)) {
741
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No LIFETIME",ctx->label);
742
ABORT(R_BAD_DATA);
743
}
744
ctx->results.refresh_response.lifetime_secs=attr->u.lifetime_secs;
745
break;
746
case NR_TURN_CLIENT_MODE_PERMISSION_REQUEST:
747
if (! nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) {
748
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No MESSAGE-INTEGRITY",ctx->label);
749
ABORT(R_BAD_DATA);
750
}
751
break;
752
#endif /* USE_TURN */
753
754
default:
755
assert(0);
756
ABORT(R_FAILED);
757
break;
758
}
759
760
/* make sure we have the most up-to-date address from this peer */
761
if (nr_transport_addr_cmp(&ctx->peer_addr, peer_addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
762
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);
763
nr_transport_addr_copy(&ctx->peer_addr, peer_addr);
764
}
765
766
if (mapped_addr) {
767
if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, &attr)) {
768
if ((r=nr_stun_transport_addr_check(&attr->u.xor_mapped_address.unmasked,
769
ctx->mapped_addr_check_mask))) {
770
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): XOR-MAPPED-ADDRESS is bogus",ctx->label);
771
ABORT(r);
772
}
773
774
if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.xor_mapped_address.unmasked))) {
775
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_transport_addr_copy failed",ctx->label);
776
ABORT(r);
777
}
778
}
779
else if (nr_stun_message_has_attribute(ctx->response, NR_STUN_ATTR_MAPPED_ADDRESS, &attr)) {
780
if ((r=nr_stun_transport_addr_check(&attr->u.mapped_address,
781
ctx->mapped_addr_check_mask))) {
782
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): MAPPED-ADDRESS is bogus",ctx->label);
783
ABORT(r);
784
}
785
786
if ((r=nr_transport_addr_copy(mapped_addr, &attr->u.mapped_address))) {
787
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): nr_transport_addr_copy failed",ctx->label);
788
ABORT(r);
789
}
790
}
791
else {
792
r_log(NR_LOG_STUN,LOG_WARNING,"STUN-CLIENT(%s): No mapped address!",ctx->label);
793
ABORT(R_BAD_DATA);
794
}
795
796
// STUN doesn't distinguish protocol in mapped address, therefore
797
// assign used protocol from peer_addr
798
if (mapped_addr->protocol!=peer_addr->protocol){
799
mapped_addr->protocol=peer_addr->protocol;
800
nr_transport_addr_fmt_addr_string(mapped_addr);
801
}
802
803
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-CLIENT(%s): Received mapped address: %s", ctx->label, mapped_addr->as_string);
804
}
805
806
ctx->state=NR_STUN_CLIENT_STATE_DONE;
807
808
_status=0;
809
abort:
810
if(_status && response_matched){
811
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);
812
}
813
814
if ((ctx->state != NR_STUN_CLIENT_STATE_RUNNING) &&
815
(ctx->state != NR_STUN_CLIENT_STATE_WAITING)) {
816
/* Cancel the timer firing */
817
if (ctx->timer_handle) {
818
NR_async_timer_cancel(ctx->timer_handle);
819
ctx->timer_handle = 0;
820
}
821
822
nr_stun_client_fire_finished_cb(ctx);
823
}
824
825
return(_status);
826
}
827
828
int nr_stun_client_ctx_destroy(nr_stun_client_ctx **ctxp)
829
{
830
nr_stun_client_ctx *ctx;
831
832
if(!ctxp || !*ctxp)
833
return(0);
834
835
ctx=*ctxp;
836
*ctxp=0;
837
838
nr_stun_client_reset(ctx);
839
840
RFREE(ctx->nonce);
841
RFREE(ctx->realm);
842
843
RFREE(ctx->label);
844
RFREE(ctx);
845
846
return(0);
847
}
848
849
850
int nr_stun_client_cancel(nr_stun_client_ctx *ctx)
851
{
852
/* Cancel the timer firing */
853
if (ctx->timer_handle){
854
NR_async_timer_cancel(ctx->timer_handle);
855
ctx->timer_handle=0;
856
}
857
858
/* Mark cancelled so we ignore any returned messsages */
859
ctx->state=NR_STUN_CLIENT_STATE_CANCELLED;
860
return(0);
861
}
862
863
int nr_stun_client_wait(nr_stun_client_ctx *ctx)
864
{
865
nr_stun_client_cancel(ctx);
866
ctx->state=NR_STUN_CLIENT_STATE_WAITING;
867
868
ctx->request_ct = ctx->maximum_transmits;
869
ctx->timeout_ms = ctx->maximum_transmits_timeout_ms;
870
NR_ASYNC_TIMER_SET(ctx->timeout_ms, nr_stun_client_timer_expired_cb, ctx, &ctx->timer_handle);
871
872
return(0);
873
}
874
875
int nr_stun_client_failed(nr_stun_client_ctx *ctx)
876
{
877
nr_stun_client_cancel(ctx);
878
ctx->state=NR_STUN_CLIENT_STATE_FAILED;
879
nr_stun_client_fire_finished_cb(ctx);
880
return(0);
881
}