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