|
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_build.c,v 1.2 2008/04/28 18:21:30 ekr Exp $"; |
|
35 |
|
36 #include <csi_platform.h> |
|
37 #include <assert.h> |
|
38 #include <errno.h> |
|
39 #include <stdio.h> |
|
40 #include <string.h> |
|
41 #include <ctype.h> |
|
42 |
|
43 #include "nr_api.h" |
|
44 #include "stun.h" |
|
45 #include "registry.h" |
|
46 #include "stun_reg.h" |
|
47 #include "nr_crypto.h" |
|
48 |
|
49 |
|
50 /* draft-ietf-behave-rfc3489bis-10.txt S 7.1 */ |
|
51 /* draft-ietf-behave-rfc3489bis-10.txt S 10.1.1 */ |
|
52 /* note that S 10.1.1 states the message MUST include MESSAGE-INTEGRITY |
|
53 * and USERNAME, but that's not correct -- for instance ICE keepalive |
|
54 * messages don't include these (See draft-ietf-mmusic-ice-18.txt S 10: |
|
55 * "If STUN is being used for keepalives, a STUN Binding Indication is |
|
56 * used. The Indication MUST NOT utilize any authentication mechanism") |
|
57 */ |
|
58 int |
|
59 nr_stun_form_request_or_indication(int mode, int msg_type, nr_stun_message **msg) |
|
60 { |
|
61 int r,_status; |
|
62 nr_stun_message *req = 0; |
|
63 |
|
64 assert(NR_STUN_GET_TYPE_CLASS(msg_type) == NR_CLASS_REQUEST |
|
65 || NR_STUN_GET_TYPE_CLASS(msg_type) == NR_CLASS_INDICATION); |
|
66 |
|
67 *msg = 0; |
|
68 |
|
69 if ((r=nr_stun_message_create(&req))) |
|
70 ABORT(r); |
|
71 |
|
72 req->header.type = msg_type; |
|
73 |
|
74 nr_crypto_random_bytes((UCHAR*)&req->header.id,sizeof(req->header.id)); |
|
75 |
|
76 switch (mode) { |
|
77 default: |
|
78 req->header.magic_cookie = NR_STUN_MAGIC_COOKIE; |
|
79 |
|
80 if ((r=nr_stun_message_add_fingerprint_attribute(req))) |
|
81 ABORT(r); |
|
82 |
|
83 break; |
|
84 |
|
85 #ifdef USE_STUND_0_96 |
|
86 case NR_STUN_MODE_STUND_0_96: |
|
87 req->header.magic_cookie = NR_STUN_MAGIC_COOKIE2; |
|
88 |
|
89 /* actually, stund 0.96 just ignores the fingerprint |
|
90 * attribute, but don't bother to send it */ |
|
91 |
|
92 break; |
|
93 #endif /* USE_STUND_0_96 */ |
|
94 |
|
95 } |
|
96 |
|
97 *msg = req; |
|
98 |
|
99 _status=0; |
|
100 abort: |
|
101 if (_status) RFREE(req); |
|
102 return _status; |
|
103 } |
|
104 |
|
105 int |
|
106 nr_stun_build_req_lt_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg) |
|
107 { |
|
108 int r,_status; |
|
109 nr_stun_message *req = 0; |
|
110 |
|
111 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req))) |
|
112 ABORT(r); |
|
113 |
|
114 if ((r=nr_stun_message_add_username_attribute(req, params->username))) |
|
115 ABORT(r); |
|
116 |
|
117 if (params->realm && params->nonce) { |
|
118 if ((r=nr_stun_message_add_realm_attribute(req, params->realm))) |
|
119 ABORT(r); |
|
120 |
|
121 if ((r=nr_stun_message_add_nonce_attribute(req, params->nonce))) |
|
122 ABORT(r); |
|
123 |
|
124 if ((r=nr_stun_message_add_message_integrity_attribute(req, params->password))) |
|
125 ABORT(r); |
|
126 } |
|
127 |
|
128 *msg = req; |
|
129 |
|
130 _status=0; |
|
131 abort: |
|
132 if (_status) nr_stun_message_destroy(&req); |
|
133 return _status; |
|
134 } |
|
135 |
|
136 int |
|
137 nr_stun_build_req_st_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg) |
|
138 { |
|
139 int r,_status; |
|
140 nr_stun_message *req = 0; |
|
141 |
|
142 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req))) |
|
143 ABORT(r); |
|
144 |
|
145 if ((r=nr_stun_message_add_username_attribute(req, params->username))) |
|
146 ABORT(r); |
|
147 |
|
148 if (params->password) { |
|
149 if ((r=nr_stun_message_add_message_integrity_attribute(req, params->password))) |
|
150 ABORT(r); |
|
151 } |
|
152 |
|
153 *msg = req; |
|
154 |
|
155 _status=0; |
|
156 abort: |
|
157 if (_status) nr_stun_message_destroy(&req); |
|
158 return _status; |
|
159 } |
|
160 |
|
161 int |
|
162 nr_stun_build_req_no_auth(nr_stun_client_stun_binding_request_params *params, nr_stun_message **msg) |
|
163 { |
|
164 int r,_status; |
|
165 nr_stun_message *req = 0; |
|
166 |
|
167 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req))) |
|
168 ABORT(r); |
|
169 |
|
170 *msg = req; |
|
171 |
|
172 _status=0; |
|
173 abort: |
|
174 if (_status) nr_stun_message_destroy(&req); |
|
175 return _status; |
|
176 } |
|
177 |
|
178 int |
|
179 nr_stun_build_keepalive(nr_stun_client_stun_keepalive_params *params, nr_stun_message **msg) |
|
180 { |
|
181 int r,_status; |
|
182 nr_stun_message *ind = 0; |
|
183 |
|
184 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_INDICATION, &ind))) |
|
185 ABORT(r); |
|
186 |
|
187 *msg = ind; |
|
188 |
|
189 _status=0; |
|
190 abort: |
|
191 if (_status) nr_stun_message_destroy(&ind); |
|
192 return _status; |
|
193 } |
|
194 |
|
195 #ifdef USE_STUND_0_96 |
|
196 int |
|
197 nr_stun_build_req_stund_0_96(nr_stun_client_stun_binding_request_stund_0_96_params *params, nr_stun_message **msg) |
|
198 { |
|
199 int r,_status; |
|
200 nr_stun_message *req = 0; |
|
201 |
|
202 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUND_0_96, NR_STUN_MSG_BINDING_REQUEST, &req))) |
|
203 ABORT(r); |
|
204 |
|
205 if ((r=nr_stun_message_add_change_request_attribute(req, 0))) |
|
206 ABORT(r); |
|
207 |
|
208 assert(! nr_stun_message_has_attribute(req, NR_STUN_ATTR_USERNAME, 0)); |
|
209 assert(! nr_stun_message_has_attribute(req, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)); |
|
210 |
|
211 *msg = req; |
|
212 |
|
213 _status=0; |
|
214 abort: |
|
215 if (_status) nr_stun_message_destroy(&req); |
|
216 return _status; |
|
217 } |
|
218 #endif /* USE_STUND_0_96 */ |
|
219 |
|
220 #ifdef USE_ICE |
|
221 int |
|
222 nr_stun_build_use_candidate(nr_stun_client_ice_use_candidate_params *params, nr_stun_message **msg) |
|
223 { |
|
224 int r,_status; |
|
225 nr_stun_message *req = 0; |
|
226 |
|
227 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req))) |
|
228 ABORT(r); |
|
229 |
|
230 if ((r=nr_stun_message_add_username_attribute(req, params->username))) |
|
231 ABORT(r); |
|
232 |
|
233 if ((r=nr_stun_message_add_message_integrity_attribute(req, ¶ms->password))) |
|
234 ABORT(r); |
|
235 |
|
236 if ((r=nr_stun_message_add_use_candidate_attribute(req))) |
|
237 ABORT(r); |
|
238 |
|
239 if ((r=nr_stun_message_add_priority_attribute(req, params->priority))) |
|
240 ABORT(r); |
|
241 |
|
242 if ((r=nr_stun_message_add_ice_controlling_attribute(req, params->tiebreaker))) |
|
243 ABORT(r); |
|
244 |
|
245 *msg = req; |
|
246 |
|
247 _status=0; |
|
248 abort: |
|
249 if (_status) nr_stun_message_destroy(&req); |
|
250 return _status; |
|
251 } |
|
252 |
|
253 int |
|
254 nr_stun_build_req_ice(nr_stun_client_ice_binding_request_params *params, nr_stun_message **msg) |
|
255 { |
|
256 int r,_status; |
|
257 nr_stun_message *req = 0; |
|
258 |
|
259 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_BINDING_REQUEST, &req))) |
|
260 ABORT(r); |
|
261 |
|
262 if ((r=nr_stun_message_add_username_attribute(req, params->username))) |
|
263 ABORT(r); |
|
264 |
|
265 if ((r=nr_stun_message_add_message_integrity_attribute(req, ¶ms->password))) |
|
266 ABORT(r); |
|
267 |
|
268 if ((r=nr_stun_message_add_priority_attribute(req, params->priority))) |
|
269 ABORT(r); |
|
270 |
|
271 switch (params->control) { |
|
272 case NR_ICE_CONTROLLING: |
|
273 if ((r=nr_stun_message_add_ice_controlling_attribute(req, params->tiebreaker))) |
|
274 ABORT(r); |
|
275 break; |
|
276 case NR_ICE_CONTROLLED: |
|
277 if ((r=nr_stun_message_add_ice_controlled_attribute(req, params->tiebreaker))) |
|
278 ABORT(r); |
|
279 break; |
|
280 default: |
|
281 assert(0); |
|
282 ABORT(R_INTERNAL); |
|
283 } |
|
284 |
|
285 *msg = req; |
|
286 |
|
287 _status=0; |
|
288 abort: |
|
289 if (_status) nr_stun_message_destroy(&req); |
|
290 return _status; |
|
291 } |
|
292 #endif /* USE_ICE */ |
|
293 |
|
294 #ifdef USE_TURN |
|
295 |
|
296 #ifndef __isascii |
|
297 #define __isascii(c) (((c) & ~0x7F) == 0) |
|
298 #endif |
|
299 |
|
300 /* Long-term passwords are computed over the key: |
|
301 |
|
302 key = MD5(username ":" realm ":" SASLprep(password)) |
|
303 |
|
304 Per RFC 5389 S 15.4 |
|
305 */ |
|
306 int |
|
307 nr_stun_compute_lt_message_integrity_password(const char *username, const char *realm, |
|
308 Data *password, Data *hmac_key) |
|
309 { |
|
310 char digest_input[1000]; |
|
311 int i; |
|
312 int r, _status; |
|
313 size_t len; |
|
314 |
|
315 /* First check that the password is ASCII. We are supposed to |
|
316 SASLprep but we don't support this yet |
|
317 TODO(ekr@rtfm.com): Add SASLprep for password. |
|
318 */ |
|
319 for (i=0; i<password->len; i++) { |
|
320 if (!__isascii(password->data[i])) |
|
321 ABORT(R_BAD_DATA); |
|
322 } |
|
323 |
|
324 if (hmac_key->len < 16) |
|
325 ABORT(R_BAD_ARGS); |
|
326 |
|
327 snprintf(digest_input, sizeof(digest_input), "%s:%s:", username, realm); |
|
328 if ((sizeof(digest_input) - strlen(digest_input)) < password->len) |
|
329 ABORT(R_BAD_DATA); |
|
330 |
|
331 len = strlen(digest_input); |
|
332 memcpy(digest_input + len, password->data, password->len); |
|
333 |
|
334 |
|
335 if (r=nr_crypto_md5((UCHAR *)digest_input, len + password->len, hmac_key->data)) |
|
336 ABORT(r); |
|
337 hmac_key->len=16; |
|
338 |
|
339 _status=0; |
|
340 abort: |
|
341 return(_status); |
|
342 } |
|
343 |
|
344 static int |
|
345 nr_stun_build_auth_params(nr_stun_client_auth_params *auth, nr_stun_message *req) |
|
346 { |
|
347 int r, _status; |
|
348 UCHAR hmac_key_d[16]; |
|
349 Data hmac_key; |
|
350 |
|
351 ATTACH_DATA(hmac_key, hmac_key_d); |
|
352 |
|
353 if (!auth->authenticate) |
|
354 goto done; |
|
355 |
|
356 assert(auth->username); |
|
357 assert(auth->password.len); |
|
358 assert(auth->realm); |
|
359 assert(auth->nonce); |
|
360 |
|
361 if (r=nr_stun_compute_lt_message_integrity_password(auth->username, |
|
362 auth->realm, |
|
363 &auth->password, |
|
364 &hmac_key)) |
|
365 ABORT(r); |
|
366 |
|
367 if (!auth->username) { |
|
368 r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no username provided"); |
|
369 ABORT(R_INTERNAL); |
|
370 } |
|
371 |
|
372 if (!auth->password.len) { |
|
373 r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no password provided"); |
|
374 ABORT(R_INTERNAL); |
|
375 } |
|
376 |
|
377 if (!auth->realm) { |
|
378 r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no realm provided"); |
|
379 ABORT(R_INTERNAL); |
|
380 } |
|
381 |
|
382 if (!auth->nonce) { |
|
383 r_log(NR_LOG_STUN, LOG_WARNING, "STUN authentication requested but no nonce provided"); |
|
384 ABORT(R_INTERNAL); |
|
385 } |
|
386 |
|
387 if ((r=nr_stun_message_add_username_attribute(req, auth->username))) |
|
388 ABORT(r); |
|
389 |
|
390 if ((r=nr_stun_message_add_realm_attribute(req, auth->realm))) |
|
391 ABORT(r); |
|
392 |
|
393 if ((r=nr_stun_message_add_nonce_attribute(req, auth->nonce))) |
|
394 ABORT(r); |
|
395 |
|
396 if ((r=nr_stun_message_add_message_integrity_attribute(req, &hmac_key))) |
|
397 ABORT(r); |
|
398 |
|
399 done: |
|
400 _status=0; |
|
401 abort: |
|
402 return(_status); |
|
403 } |
|
404 |
|
405 int |
|
406 nr_stun_build_allocate_request(nr_stun_client_auth_params *auth, nr_stun_client_allocate_request_params *params, nr_stun_message **msg) |
|
407 { |
|
408 int r,_status; |
|
409 nr_stun_message *req = 0; |
|
410 |
|
411 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_ALLOCATE_REQUEST, &req))) |
|
412 ABORT(r); |
|
413 |
|
414 if ((r=nr_stun_message_add_requested_transport_attribute(req, NR_STUN_ATTR_REQUESTED_TRANSPORT_UDP))) |
|
415 ABORT(r); |
|
416 |
|
417 if ((r=nr_stun_message_add_lifetime_attribute(req, params->lifetime_secs))) |
|
418 ABORT(r); |
|
419 |
|
420 /* TODO(ekr@rtfm.com): Add the SOFTWARE attribute (Firefox bug 857666) */ |
|
421 |
|
422 if ((r=nr_stun_build_auth_params(auth, req))) |
|
423 ABORT(r); |
|
424 |
|
425 *msg = req; |
|
426 |
|
427 _status=0; |
|
428 abort: |
|
429 if (_status) nr_stun_message_destroy(&req); |
|
430 return _status; |
|
431 } |
|
432 |
|
433 |
|
434 int nr_stun_build_refresh_request(nr_stun_client_auth_params *auth, nr_stun_client_refresh_request_params *params, nr_stun_message **msg) |
|
435 { |
|
436 int r,_status; |
|
437 nr_stun_message *req = 0; |
|
438 |
|
439 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_REFRESH_REQUEST, &req))) |
|
440 ABORT(r); |
|
441 |
|
442 if ((r=nr_stun_message_add_lifetime_attribute(req, params->lifetime_secs))) |
|
443 ABORT(r); |
|
444 |
|
445 |
|
446 /* TODO(ekr@rtfm.com): Add the SOFTWARE attribute (Firefox bug 857666) */ |
|
447 |
|
448 if ((r=nr_stun_build_auth_params(auth, req))) |
|
449 ABORT(r); |
|
450 |
|
451 *msg = req; |
|
452 |
|
453 _status=0; |
|
454 abort: |
|
455 if (_status) nr_stun_message_destroy(&req); |
|
456 return _status; |
|
457 } |
|
458 |
|
459 |
|
460 int nr_stun_build_permission_request(nr_stun_client_auth_params *auth, nr_stun_client_permission_request_params *params, nr_stun_message **msg) |
|
461 { |
|
462 int r,_status; |
|
463 nr_stun_message *req = 0; |
|
464 |
|
465 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_PERMISSION_REQUEST, &req))) |
|
466 ABORT(r); |
|
467 |
|
468 if ((r=nr_stun_message_add_xor_peer_address_attribute(req, ¶ms->remote_addr))) |
|
469 ABORT(r); |
|
470 |
|
471 if ((r=nr_stun_build_auth_params(auth, req))) |
|
472 ABORT(r); |
|
473 |
|
474 *msg = req; |
|
475 |
|
476 _status=0; |
|
477 abort: |
|
478 if (_status) nr_stun_message_destroy(&req); |
|
479 return _status; |
|
480 } |
|
481 |
|
482 int |
|
483 nr_stun_build_send_indication(nr_stun_client_send_indication_params *params, nr_stun_message **msg) |
|
484 { |
|
485 int r,_status; |
|
486 nr_stun_message *ind = 0; |
|
487 |
|
488 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_SEND_INDICATION, &ind))) |
|
489 ABORT(r); |
|
490 |
|
491 if ((r=nr_stun_message_add_xor_peer_address_attribute(ind, ¶ms->remote_addr))) |
|
492 ABORT(r); |
|
493 |
|
494 if ((r=nr_stun_message_add_data_attribute(ind, params->data.data, params->data.len))) |
|
495 ABORT(r); |
|
496 |
|
497 *msg = ind; |
|
498 |
|
499 _status=0; |
|
500 abort: |
|
501 if (_status) nr_stun_message_destroy(&ind); |
|
502 return _status; |
|
503 } |
|
504 |
|
505 int |
|
506 nr_stun_build_data_indication(nr_stun_client_data_indication_params *params, nr_stun_message **msg) |
|
507 { |
|
508 int r,_status; |
|
509 nr_stun_message *ind = 0; |
|
510 |
|
511 if ((r=nr_stun_form_request_or_indication(NR_STUN_MODE_STUN, NR_STUN_MSG_DATA_INDICATION, &ind))) |
|
512 ABORT(r); |
|
513 |
|
514 if ((r=nr_stun_message_add_xor_peer_address_attribute(ind, ¶ms->remote_addr))) |
|
515 ABORT(r); |
|
516 |
|
517 if ((r=nr_stun_message_add_data_attribute(ind, params->data.data, params->data.len))) |
|
518 ABORT(r); |
|
519 |
|
520 *msg = ind; |
|
521 |
|
522 _status=0; |
|
523 abort: |
|
524 if (_status) nr_stun_message_destroy(&ind); |
|
525 return _status; |
|
526 } |
|
527 |
|
528 #endif /* USE_TURN */ |
|
529 |
|
530 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1.1 */ |
|
531 int |
|
532 nr_stun_form_success_response(nr_stun_message *req, nr_transport_addr *from, Data *password, nr_stun_message *res) |
|
533 { |
|
534 int r,_status; |
|
535 int request_method; |
|
536 char server_name[NR_STUN_MAX_SERVER_BYTES+1]; /* +1 for \0 */ |
|
537 |
|
538 /* set up information for default response */ |
|
539 |
|
540 request_method = NR_STUN_GET_TYPE_METHOD(req->header.type); |
|
541 res->header.type = NR_STUN_TYPE(request_method, NR_CLASS_RESPONSE); |
|
542 res->header.magic_cookie = req->header.magic_cookie; |
|
543 memcpy(&res->header.id, &req->header.id, sizeof(res->header.id)); |
|
544 |
|
545 r_log(NR_LOG_STUN, LOG_DEBUG, "Mapped Address = %s", from->as_string); |
|
546 |
|
547 if ((r=nr_stun_message_add_xor_mapped_address_attribute(res, from))) |
|
548 ABORT(r); |
|
549 |
|
550 if (!NR_reg_get_string(NR_STUN_REG_PREF_SERVER_NAME, server_name, sizeof(server_name))) { |
|
551 if ((r=nr_stun_message_add_server_attribute(res, server_name))) |
|
552 ABORT(r); |
|
553 } |
|
554 |
|
555 if (res->header.magic_cookie == NR_STUN_MAGIC_COOKIE) { |
|
556 if (password != 0) { |
|
557 if ((r=nr_stun_message_add_message_integrity_attribute(res, password))) |
|
558 ABORT(r); |
|
559 } |
|
560 |
|
561 if ((r=nr_stun_message_add_fingerprint_attribute(res))) |
|
562 ABORT(r); |
|
563 } |
|
564 |
|
565 _status=0; |
|
566 abort: |
|
567 return _status; |
|
568 } |
|
569 |
|
570 /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1.1 */ |
|
571 void |
|
572 nr_stun_form_error_response(nr_stun_message *req, nr_stun_message* res, int number, char* msg) |
|
573 { |
|
574 char *str; |
|
575 int request_method; |
|
576 char server_name[NR_STUN_MAX_SERVER_BYTES+1]; /* +1 for \0 */ |
|
577 |
|
578 if (number < 300 || number > 699) |
|
579 number = 500; |
|
580 |
|
581 r_log(NR_LOG_STUN, LOG_INFO, "Responding with error %d: %s", number, msg); |
|
582 |
|
583 request_method = NR_STUN_GET_TYPE_METHOD(req->header.type); |
|
584 res->header.type = NR_STUN_TYPE(request_method, NR_CLASS_ERROR_RESPONSE); |
|
585 res->header.magic_cookie = req->header.magic_cookie; |
|
586 memcpy(&res->header.id, &req->header.id, sizeof(res->header.id)); |
|
587 |
|
588 /* during development we should never see 500s (hopefully not in deployment either) */ |
|
589 |
|
590 str = 0; |
|
591 switch (number) { |
|
592 case 300: str = "Try Alternate"; break; |
|
593 case 400: str = "Bad Request"; break; |
|
594 case 401: str = "Unauthorized"; break; |
|
595 case 420: str = "Unknown Attribute"; break; |
|
596 case 438: str = "Stale Nonce"; break; |
|
597 #ifdef USE_ICE |
|
598 case 487: str = "Role Conflict"; break; |
|
599 #endif |
|
600 case 500: str = "Server Error"; break; |
|
601 } |
|
602 if (str == 0) { |
|
603 str = "Unknown"; |
|
604 } |
|
605 |
|
606 if (nr_stun_message_add_error_code_attribute(res, number, str)) { |
|
607 assert(0); /* should never happen */ |
|
608 } |
|
609 |
|
610 if (!NR_reg_get_string(NR_STUN_REG_PREF_SERVER_NAME, server_name, sizeof(server_name))) { |
|
611 nr_stun_message_add_server_attribute(res, server_name); |
|
612 } |
|
613 } |
|
614 |