1 /* $Id$ */
2 /*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 #include <pjnath/stun_msg.h>
21 #include <pjnath/errno.h>
22 #include <pjlib-util/crc32.h>
23 #include <pjlib-util/hmac_sha1.h>
24 #include <pj/assert.h>
25 #include <pj/log.h>
26 #include <pj/os.h>
27 #include <pj/pool.h>
28 #include <pj/rand.h>
29 #include <pj/string.h>
30
31 #define THIS_FILE "stun_msg.c"
32 #define STUN_XOR_FINGERPRINT 0x5354554eL
33
34 static int padding_char;
35
36 static const char *stun_method_names[PJ_STUN_METHOD_MAX] =
37 {
38 "Unknown", /* 0 */
39 "Binding", /* 1 */
40 "SharedSecret", /* 2 */
41 "Allocate", /* 3 */
42 "Refresh", /* 4 */
43 "???", /* 5 */
44 "Send", /* 6 */
45 "Data", /* 7 */
46 "CreatePermission", /* 8 */
47 "ChannelBind", /* 9 */
48 "Connect", /* 10 */
49 "ConnectionBind", /* 11 */
50 "ConnectionAttempt", /* 12 */
51 };
52
53 static struct
54 {
55 int err_code;
56 const char *err_msg;
57 } stun_err_msg_map[] =
58 {
59 { PJ_STUN_SC_TRY_ALTERNATE, "Try Alternate"},
60 { PJ_STUN_SC_BAD_REQUEST, "Bad Request"},
61 { PJ_STUN_SC_UNAUTHORIZED, "Unauthorized"},
62 { PJ_STUN_SC_FORBIDDEN, "Forbidden"},
63 { PJ_STUN_SC_UNKNOWN_ATTRIBUTE, "Unknown Attribute"},
64 //{ PJ_STUN_SC_STALE_CREDENTIALS, "Stale Credentials"},
65 //{ PJ_STUN_SC_INTEGRITY_CHECK_FAILURE, "Integrity Check Failure"},
66 //{ PJ_STUN_SC_MISSING_USERNAME, "Missing Username"},
67 //{ PJ_STUN_SC_USE_TLS, "Use TLS"},
68 //{ PJ_STUN_SC_MISSING_REALM, "Missing Realm"},
69 //{ PJ_STUN_SC_MISSING_NONCE, "Missing Nonce"},
70 //{ PJ_STUN_SC_UNKNOWN_USERNAME, "Unknown Username"},
71 { PJ_STUN_SC_ALLOCATION_MISMATCH, "Allocation Mismatch"},
72 { PJ_STUN_SC_STALE_NONCE, "Stale Nonce"},
73 { PJ_STUN_SC_TRANSITIONING, "Active Destination Already Set"},
74 { PJ_STUN_SC_WRONG_CREDENTIALS, "Wrong Credentials"},
75 { PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO, "Unsupported Transport Protocol"},
76 { PJ_STUN_SC_OPER_TCP_ONLY, "Operation for TCP Only"},
77 { PJ_STUN_SC_CONNECTION_FAILURE, "Connection Failure"},
78 { PJ_STUN_SC_CONNECTION_TIMEOUT, "Connection Timeout"},
79 { PJ_STUN_SC_ALLOCATION_QUOTA_REACHED, "Allocation Quota Reached"},
80 { PJ_STUN_SC_ROLE_CONFLICT, "Role Conflict"},
81 { PJ_STUN_SC_SERVER_ERROR, "Server Error"},
82 { PJ_STUN_SC_INSUFFICIENT_CAPACITY, "Insufficient Capacity"},
83 { PJ_STUN_SC_GLOBAL_FAILURE, "Global Failure"}
84 };
85
86
87
88 struct attr_desc
89 {
90 const char *name;
91 pj_status_t (*decode_attr)(pj_pool_t *pool, const pj_uint8_t *buf,
92 const pj_stun_msg_hdr *msghdr, void **p_attr);
93 pj_status_t (*encode_attr)(const void *a, pj_uint8_t *buf,
94 unsigned len, const pj_stun_msg_hdr *msghdr,
95 unsigned *printed);
96 void* (*clone_attr)(pj_pool_t *pool, const void *src);
97 };
98
99 static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
100 const pj_uint8_t *buf,
101 const pj_stun_msg_hdr *msghdr,
102 void **p_attr);
103 static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
104 const pj_uint8_t *buf,
105 const pj_stun_msg_hdr *msghdr,
106 void **p_attr);
107 static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf,
108 unsigned len,
109 const pj_stun_msg_hdr *msghdr,
110 unsigned *printed);
111 static void* clone_sockaddr_attr(pj_pool_t *pool, const void *src);
112 static pj_status_t decode_string_attr(pj_pool_t *pool,
113 const pj_uint8_t *buf,
114 const pj_stun_msg_hdr *msghdr,
115 void **p_attr);
116 static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
117 unsigned len,
118 const pj_stun_msg_hdr *msghdr,
119 unsigned *printed);
120 static void* clone_string_attr(pj_pool_t *pool, const void *src);
121 static pj_status_t decode_msgint_attr(pj_pool_t *pool,
122 const pj_uint8_t *buf,
123 const pj_stun_msg_hdr *msghdr,
124 void **p_attr);
125 static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf,
126 unsigned len,
127 const pj_stun_msg_hdr *msghdr,
128 unsigned *printed);
129 static void* clone_msgint_attr(pj_pool_t *pool, const void *src);
130 static pj_status_t decode_errcode_attr(pj_pool_t *pool,
131 const pj_uint8_t *buf,
132 const pj_stun_msg_hdr *msghdr,
133 void **p_attr);
134 static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf,
135 unsigned len,
136 const pj_stun_msg_hdr *msghdr,
137 unsigned *printed);
138 static void* clone_errcode_attr(pj_pool_t *pool, const void *src);
139 static pj_status_t decode_unknown_attr(pj_pool_t *pool,
140 const pj_uint8_t *buf,
141 const pj_stun_msg_hdr *msghdr,
142 void **p_attr);
143 static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
144 unsigned len,
145 const pj_stun_msg_hdr *msghdr,
146 unsigned *printed);
147 static void* clone_unknown_attr(pj_pool_t *pool, const void *src);
148 static pj_status_t decode_uint_attr(pj_pool_t *pool,
149 const pj_uint8_t *buf,
150 const pj_stun_msg_hdr *msghdr,
151 void **p_attr);
152 static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf,
153 unsigned len,
154 const pj_stun_msg_hdr *msghdr,
155 unsigned *printed);
156 static void* clone_uint_attr(pj_pool_t *pool, const void *src);
157 static pj_status_t decode_uint64_attr(pj_pool_t *pool,
158 const pj_uint8_t *buf,
159 const pj_stun_msg_hdr *msghdr,
160 void **p_attr);
161 static pj_status_t encode_uint64_attr(const void *a, pj_uint8_t *buf,
162 unsigned len,
163 const pj_stun_msg_hdr *msghdr,
164 unsigned *printed);
165 static void* clone_uint64_attr(pj_pool_t *pool, const void *src);
166 static pj_status_t decode_binary_attr(pj_pool_t *pool,
167 const pj_uint8_t *buf,
168 const pj_stun_msg_hdr *msghdr,
169 void **p_attr);
170 static pj_status_t encode_binary_attr(const void *a, pj_uint8_t *buf,
171 unsigned len,
172 const pj_stun_msg_hdr *msghdr,
173 unsigned *printed);
174 static void* clone_binary_attr(pj_pool_t *pool, const void *src);
175 static pj_status_t decode_empty_attr(pj_pool_t *pool,
176 const pj_uint8_t *buf,
177 const pj_stun_msg_hdr *msghdr,
178 void **p_attr);
179 static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
180 unsigned len,
181 const pj_stun_msg_hdr *msghdr,
182 unsigned *printed);
183 static void* clone_empty_attr(pj_pool_t *pool, const void *src);
184
185 static struct attr_desc mandatory_attr_desc[] =
186 {
187 {
188 /* type zero */
189 NULL,
190 NULL,
191 NULL,
192 NULL
193 },
194 {
195 /* PJ_STUN_ATTR_MAPPED_ADDR, */
196 "MAPPED-ADDRESS",
197 &decode_sockaddr_attr,
198 &encode_sockaddr_attr,
199 &clone_sockaddr_attr
200 },
201 {
202 /* PJ_STUN_ATTR_RESPONSE_ADDR, */
203 "RESPONSE-ADDRESS",
204 &decode_sockaddr_attr,
205 &encode_sockaddr_attr,
206 &clone_sockaddr_attr
207 },
208 {
209 /* PJ_STUN_ATTR_CHANGE_REQUEST, */
210 "CHANGE-REQUEST",
211 &decode_uint_attr,
212 &encode_uint_attr,
213 &clone_uint_attr
214 },
215 {
216 /* PJ_STUN_ATTR_SOURCE_ADDR, */
217 "SOURCE-ADDRESS",
218 &decode_sockaddr_attr,
219 &encode_sockaddr_attr,
220 &clone_sockaddr_attr
221 },
222 {
223 /* PJ_STUN_ATTR_CHANGED_ADDR, */
224 "CHANGED-ADDRESS",
225 &decode_sockaddr_attr,
226 &encode_sockaddr_attr,
227 &clone_sockaddr_attr
228 },
229 {
230 /* PJ_STUN_ATTR_USERNAME, */
231 "USERNAME",
232 &decode_string_attr,
233 &encode_string_attr,
234 &clone_string_attr
235 },
236 {
237 /* PJ_STUN_ATTR_PASSWORD, */
238 "PASSWORD",
239 &decode_string_attr,
240 &encode_string_attr,
241 &clone_string_attr
242 },
243 {
244 /* PJ_STUN_ATTR_MESSAGE_INTEGRITY, */
245 "MESSAGE-INTEGRITY",
246 &decode_msgint_attr,
247 &encode_msgint_attr,
248 &clone_msgint_attr
249 },
250 {
251 /* PJ_STUN_ATTR_ERROR_CODE, */
252 "ERROR-CODE",
253 &decode_errcode_attr,
254 &encode_errcode_attr,
255 &clone_errcode_attr
256 },
257 {
258 /* PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, */
259 "UNKNOWN-ATTRIBUTES",
260 &decode_unknown_attr,
261 &encode_unknown_attr,
262 &clone_unknown_attr
263 },
264 {
265 /* PJ_STUN_ATTR_REFLECTED_FROM, */
266 "REFLECTED-FROM",
267 &decode_sockaddr_attr,
268 &encode_sockaddr_attr,
269 &clone_sockaddr_attr
270 },
271 {
272 /* PJ_STUN_ATTR_CHANNEL_NUMBER (0x000C) */
273 "CHANNEL-NUMBER",
274 &decode_uint_attr,
275 &encode_uint_attr,
276 &clone_uint_attr
277 },
278 {
279 /* PJ_STUN_ATTR_LIFETIME, */
280 "LIFETIME",
281 &decode_uint_attr,
282 &encode_uint_attr,
283 &clone_uint_attr
284 },
285 {
286 /* ID 0x000E is not assigned */
287 NULL,
288 NULL,
289 NULL,
290 NULL
291 },
292 {
293 /* PJ_STUN_ATTR_MAGIC_COOKIE */
294 "MAGIC-COOKIE",
295 &decode_uint_attr,
296 &encode_uint_attr,
297 &clone_uint_attr
298 },
299 {
300 /* PJ_STUN_ATTR_BANDWIDTH, */
301 "BANDWIDTH",
302 &decode_uint_attr,
303 &encode_uint_attr,
304 &clone_uint_attr
305 },
306 {
307 /* ID 0x0011 is not assigned */
308 NULL,
309 NULL,
310 NULL,
311 NULL
312 },
313 {
314 /* PJ_STUN_ATTR_XOR_PEER_ADDRESS, */
315 "XOR-PEER-ADDRESS",
316 &decode_xored_sockaddr_attr,
317 &encode_sockaddr_attr,
318 &clone_sockaddr_attr
319 },
320 {
321 /* PJ_STUN_ATTR_DATA, */
322 "DATA",
323 &decode_binary_attr,
324 &encode_binary_attr,
325 &clone_binary_attr
326 },
327 {
328 /* PJ_STUN_ATTR_REALM, */
329 "REALM",
330 &decode_string_attr,
331 &encode_string_attr,
332 &clone_string_attr
333 },
334 {
335 /* PJ_STUN_ATTR_NONCE, */
336 "NONCE",
337 &decode_string_attr,
338 &encode_string_attr,
339 &clone_string_attr
340 },
341 {
342 /* PJ_STUN_ATTR_XOR_RELAYED_ADDR, */
343 "XOR-RELAYED-ADDRESS",
344 &decode_xored_sockaddr_attr,
345 &encode_sockaddr_attr,
346 &clone_sockaddr_attr
347 },
348 {
349 /* PJ_STUN_ATTR_REQUESTED_ADDR_FAMILY, */
350 "REQUESTED-ADDRESS-FAMILY",
351 &decode_uint_attr,
352 &encode_uint_attr,
353 &clone_uint_attr
354 },
355 {
356 /* PJ_STUN_ATTR_EVEN_PORT, */
357 "EVEN-PORT",
358 &decode_uint_attr,
359 &encode_uint_attr,
360 &clone_uint_attr
361 },
362 {
363 /* PJ_STUN_ATTR_REQUESTED_TRANSPORT, */
364 "REQUESTED-TRANSPORT",
365 &decode_uint_attr,
366 &encode_uint_attr,
367 &clone_uint_attr
368 },
369 {
370 /* PJ_STUN_ATTR_DONT_FRAGMENT */
371 "DONT-FRAGMENT",
372 &decode_empty_attr,
373 &encode_empty_attr,
374 &clone_empty_attr
375 },
376 {
377 /* ID 0x001B is not assigned */
378 NULL,
379 NULL,
380 NULL,
381 NULL
382 },
383 {
384 /* ID 0x001C is not assigned */
385 NULL,
386 NULL,
387 NULL,
388 NULL
389 },
390 {
391 /* ID 0x001D is not assigned */
392 NULL,
393 NULL,
394 NULL,
395 NULL
396 },
397 {
398 /* ID 0x001E is not assigned */
399 NULL,
400 NULL,
401 NULL,
402 NULL
403 },
404 {
405 /* ID 0x001F is not assigned */
406 NULL,
407 NULL,
408 NULL,
409 NULL
410 },
411 {
412 /* PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, */
413 "XOR-MAPPED-ADDRESS",
414 &decode_xored_sockaddr_attr,
415 &encode_sockaddr_attr,
416 &clone_sockaddr_attr
417 },
418 {
419 /* PJ_STUN_ATTR_TIMER_VAL, */
420 "TIMER-VAL",
421 &decode_uint_attr,
422 &encode_uint_attr,
423 &clone_uint_attr
424 },
425 {
426 /* PJ_STUN_ATTR_RESERVATION_TOKEN, */
427 "RESERVATION-TOKEN",
428 &decode_uint64_attr,
429 &encode_uint64_attr,
430 &clone_uint64_attr
431 },
432 {
433 /* PJ_STUN_ATTR_XOR_REFLECTED_FROM, */
434 "XOR-REFLECTED-FROM",
435 &decode_xored_sockaddr_attr,
436 &encode_sockaddr_attr,
437 &clone_sockaddr_attr
438 },
439 {
440 /* PJ_STUN_ATTR_PRIORITY, */
441 "PRIORITY",
442 &decode_uint_attr,
443 &encode_uint_attr,
444 &clone_uint_attr
445 },
446 {
447 /* PJ_STUN_ATTR_USE_CANDIDATE, */
448 "USE-CANDIDATE",
449 &decode_empty_attr,
450 &encode_empty_attr,
451 &clone_empty_attr
452 },
453 {
454 /* ID 0x0026 is not assigned */
455 NULL,
456 NULL,
457 NULL,
458 NULL
459 },
460 {
461 /* ID 0x0027 is not assigned */
462 NULL,
463 NULL,
464 NULL,
465 NULL
466 },
467 {
468 /* ID 0x0028 is not assigned */
469 NULL,
470 NULL,
471 NULL,
472 NULL
473 },
474 {
475 /* ID 0x0029 is not assigned */
476 NULL,
477 NULL,
478 NULL,
479 NULL
480 },
481 {
482 /* PJ_STUN_ATTR_CONNECTION_ID, */
483 "CONNECTION-ID",
484 &decode_uint_attr,
485 &encode_uint_attr,
486 &clone_uint_attr
487 },
488 {
489 /* ID 0x002b is not assigned */
490 NULL,
491 NULL,
492 NULL,
493 NULL
494 },
495 {
496 /* ID 0x002c is not assigned */
497 NULL,
498 NULL,
499 NULL,
500 NULL
501 },
502 {
503 /* ID 0x002d is not assigned */
504 NULL,
505 NULL,
506 NULL,
507 NULL
508 },
509 {
510 /* ID 0x002e is not assigned */
511 NULL,
512 NULL,
513 NULL,
514 NULL
515 },
516 {
517 /* ID 0x002f is not assigned */
518 NULL,
519 NULL,
520 NULL,
521 NULL
522 },
523 {
524 /* PJ_STUN_ATTR_ICMP, */
525 "ICMP",
526 &decode_uint_attr,
527 &encode_uint_attr,
528 &clone_uint_attr
529 },
530
531 /* Sentinel */
532 {
533 /* PJ_STUN_ATTR_END_MANDATORY_ATTR */
534 NULL,
535 NULL,
536 NULL,
537 NULL
538 }
539 };
540
541 static struct attr_desc extended_attr_desc[] =
542 {
543 {
544 /* ID 0x8021 is not assigned */
545 NULL,
546 NULL,
547 NULL,
548 NULL
549 },
550 {
551 /* PJ_STUN_ATTR_SOFTWARE, */
552 "SOFTWARE",
553 &decode_string_attr,
554 &encode_string_attr,
555 &clone_string_attr
556 },
557 {
558 /* PJ_STUN_ATTR_ALTERNATE_SERVER, */
559 "ALTERNATE-SERVER",
560 &decode_sockaddr_attr,
561 &encode_sockaddr_attr,
562 &clone_sockaddr_attr
563 },
564 {
565 /* PJ_STUN_ATTR_REFRESH_INTERVAL, */
566 "REFRESH-INTERVAL",
567 &decode_uint_attr,
568 &encode_uint_attr,
569 &clone_uint_attr
570 },
571 {
572 /* ID 0x8025 is not assigned*/
573 NULL,
574 NULL,
575 NULL,
576 NULL
577 },
578 {
579 /* PADDING, 0x8026 */
580 NULL,
581 NULL,
582 NULL,
583 NULL
584 },
585 {
586 /* CACHE-TIMEOUT, 0x8027 */
587 NULL,
588 NULL,
589 NULL,
590 NULL
591 },
592 {
593 /* PJ_STUN_ATTR_FINGERPRINT, */
594 "FINGERPRINT",
595 &decode_uint_attr,
596 &encode_uint_attr,
597 &clone_uint_attr
598 },
599 {
600 /* PJ_STUN_ATTR_ICE_CONTROLLED, */
601 "ICE-CONTROLLED",
602 &decode_uint64_attr,
603 &encode_uint64_attr,
604 &clone_uint64_attr
605 },
606 {
607 /* PJ_STUN_ATTR_ICE_CONTROLLING, */
608 "ICE-CONTROLLING",
609 &decode_uint64_attr,
610 &encode_uint64_attr,
611 &clone_uint64_attr
612 }
613 };
614
615
616
617 /*
618 * Get STUN message type name.
619 */
pj_stun_get_method_name(unsigned msg_type)620 PJ_DEF(const char*) pj_stun_get_method_name(unsigned msg_type)
621 {
622 unsigned method = PJ_STUN_GET_METHOD(msg_type);
623
624 if (method >= PJ_ARRAY_SIZE(stun_method_names))
625 return "???";
626
627 return stun_method_names[method];
628 }
629
630
631 /*
632 * Get STUN message class name.
633 */
pj_stun_get_class_name(unsigned msg_type)634 PJ_DEF(const char*) pj_stun_get_class_name(unsigned msg_type)
635 {
636 if (PJ_STUN_IS_REQUEST(msg_type))
637 return "request";
638 else if (PJ_STUN_IS_SUCCESS_RESPONSE(msg_type))
639 return "success response";
640 else if (PJ_STUN_IS_ERROR_RESPONSE(msg_type))
641 return "error response";
642 else if (PJ_STUN_IS_INDICATION(msg_type))
643 return "indication";
644 else
645 return "???";
646 }
647
648
find_attr_desc(unsigned attr_type)649 static const struct attr_desc *find_attr_desc(unsigned attr_type)
650 {
651 struct attr_desc *desc;
652
653 /* Check that attr_desc array is valid */
654 pj_assert(PJ_ARRAY_SIZE(mandatory_attr_desc)==
655 PJ_STUN_ATTR_END_MANDATORY_ATTR+1);
656 pj_assert(mandatory_attr_desc[PJ_STUN_ATTR_END_MANDATORY_ATTR].decode_attr
657 == NULL);
658 pj_assert(mandatory_attr_desc[PJ_STUN_ATTR_USE_CANDIDATE].decode_attr
659 == &decode_empty_attr);
660 pj_assert(PJ_ARRAY_SIZE(extended_attr_desc) ==
661 PJ_STUN_ATTR_END_EXTENDED_ATTR-PJ_STUN_ATTR_START_EXTENDED_ATTR);
662
663 if (attr_type < PJ_STUN_ATTR_END_MANDATORY_ATTR)
664 desc = &mandatory_attr_desc[attr_type];
665 else if (attr_type >= PJ_STUN_ATTR_START_EXTENDED_ATTR &&
666 attr_type < PJ_STUN_ATTR_END_EXTENDED_ATTR)
667 desc = &extended_attr_desc[attr_type-PJ_STUN_ATTR_START_EXTENDED_ATTR];
668 else
669 return NULL;
670
671 return desc->decode_attr == NULL ? NULL : desc;
672 }
673
674
675 /*
676 * Get STUN attribute name.
677 */
pj_stun_get_attr_name(unsigned attr_type)678 PJ_DEF(const char*) pj_stun_get_attr_name(unsigned attr_type)
679 {
680 const struct attr_desc *attr_desc;
681
682 attr_desc = find_attr_desc(attr_type);
683 if (!attr_desc || attr_desc->name==NULL)
684 return "???";
685
686 return attr_desc->name;
687 }
688
689
690 /**
691 * Get STUN standard reason phrase for the specified error code.
692 */
pj_stun_get_err_reason(int err_code)693 PJ_DEF(pj_str_t) pj_stun_get_err_reason(int err_code)
694 {
695 #if 0
696 /* Find error using linear search */
697 unsigned i;
698
699 for (i=0; i<PJ_ARRAY_SIZE(stun_err_msg_map); ++i) {
700 if (stun_err_msg_map[i].err_code == err_code)
701 return pj_str((char*)stun_err_msg_map[i].err_msg);
702 }
703 return pj_str(NULL);
704 #else
705 /* Find error message using binary search */
706 int first = 0;
707 int n = PJ_ARRAY_SIZE(stun_err_msg_map);
708
709 while (n > 0) {
710 int half = n/2;
711 int mid = first + half;
712
713 if (stun_err_msg_map[mid].err_code < err_code) {
714 first = mid+1;
715 n -= (half+1);
716 } else if (stun_err_msg_map[mid].err_code > err_code) {
717 n = half;
718 } else {
719 first = mid;
720 break;
721 }
722 }
723
724
725 if (stun_err_msg_map[first].err_code == err_code) {
726 return pj_str((char*)stun_err_msg_map[first].err_msg);
727 } else {
728 return pj_str(NULL);
729 }
730 #endif
731 }
732
733
734 /*
735 * Set padding character.
736 */
pj_stun_set_padding_char(int chr)737 PJ_DEF(int) pj_stun_set_padding_char(int chr)
738 {
739 int old_pad = padding_char;
740 padding_char = chr;
741 return old_pad;
742 }
743
744
745 //////////////////////////////////////////////////////////////////////////////
746
747
748 #define INIT_ATTR(a,t,l) (a)->hdr.type=(pj_uint16_t)(t), \
749 (a)->hdr.length=(pj_uint16_t)(l)
750 #define ATTR_HDR_LEN 4
751
GETVAL16H(const pj_uint8_t * buf,unsigned pos)752 static pj_uint16_t GETVAL16H(const pj_uint8_t *buf, unsigned pos)
753 {
754 return (pj_uint16_t) ((buf[pos + 0] << 8) | \
755 (buf[pos + 1] << 0));
756 }
757
758 /*unused PJ_INLINE(pj_uint16_t) GETVAL16N(const pj_uint8_t *buf, unsigned pos)
759 {
760 return pj_htons(GETVAL16H(buf,pos));
761 }*/
762
PUTVAL16H(pj_uint8_t * buf,unsigned pos,pj_uint16_t hval)763 static void PUTVAL16H(pj_uint8_t *buf, unsigned pos, pj_uint16_t hval)
764 {
765 buf[pos+0] = (pj_uint8_t) ((hval & 0xFF00) >> 8);
766 buf[pos+1] = (pj_uint8_t) ((hval & 0x00FF) >> 0);
767 }
768
GETVAL32H(const pj_uint8_t * buf,unsigned pos)769 PJ_INLINE(pj_uint32_t) GETVAL32H(const pj_uint8_t *buf, unsigned pos)
770 {
771 return (pj_uint32_t) ((buf[pos + 0] << 24UL) | \
772 (buf[pos + 1] << 16UL) | \
773 (buf[pos + 2] << 8UL) | \
774 (buf[pos + 3] << 0UL));
775 }
776
777 /*unused PJ_INLINE(pj_uint32_t) GETVAL32N(const pj_uint8_t *buf, unsigned pos)
778 {
779 return pj_htonl(GETVAL32H(buf,pos));
780 }*/
781
PUTVAL32H(pj_uint8_t * buf,unsigned pos,pj_uint32_t hval)782 static void PUTVAL32H(pj_uint8_t *buf, unsigned pos, pj_uint32_t hval)
783 {
784 buf[pos+0] = (pj_uint8_t) ((hval & 0xFF000000UL) >> 24);
785 buf[pos+1] = (pj_uint8_t) ((hval & 0x00FF0000UL) >> 16);
786 buf[pos+2] = (pj_uint8_t) ((hval & 0x0000FF00UL) >> 8);
787 buf[pos+3] = (pj_uint8_t) ((hval & 0x000000FFUL) >> 0);
788 }
789
GETVAL64H(const pj_uint8_t * buf,unsigned pos,pj_timestamp * ts)790 static void GETVAL64H(const pj_uint8_t *buf, unsigned pos, pj_timestamp *ts)
791 {
792 ts->u32.hi = GETVAL32H(buf, pos);
793 ts->u32.lo = GETVAL32H(buf, pos+4);
794 }
795
PUTVAL64H(pj_uint8_t * buf,unsigned pos,const pj_timestamp * ts)796 static void PUTVAL64H(pj_uint8_t *buf, unsigned pos, const pj_timestamp *ts)
797 {
798 PUTVAL32H(buf, pos, ts->u32.hi);
799 PUTVAL32H(buf, pos+4, ts->u32.lo);
800 }
801
802
GETATTRHDR(const pj_uint8_t * buf,pj_stun_attr_hdr * hdr)803 static void GETATTRHDR(const pj_uint8_t *buf, pj_stun_attr_hdr *hdr)
804 {
805 hdr->type = GETVAL16H(buf, 0);
806 hdr->length = GETVAL16H(buf, 2);
807 }
808
809 //////////////////////////////////////////////////////////////////////////////
810 /*
811 * STUN generic IP address container
812 */
813 #define STUN_GENERIC_IPV4_ADDR_LEN 8
814 #define STUN_GENERIC_IPV6_ADDR_LEN 20
815
816 /*
817 * Init sockaddr attr
818 */
pj_stun_sockaddr_attr_init(pj_stun_sockaddr_attr * attr,int attr_type,pj_bool_t xor_ed,const pj_sockaddr_t * addr,unsigned addr_len)819 PJ_DEF(pj_status_t) pj_stun_sockaddr_attr_init( pj_stun_sockaddr_attr *attr,
820 int attr_type,
821 pj_bool_t xor_ed,
822 const pj_sockaddr_t *addr,
823 unsigned addr_len)
824 {
825 unsigned attr_len;
826
827 PJ_ASSERT_RETURN(attr && addr_len && addr, PJ_EINVAL);
828 PJ_ASSERT_RETURN(addr_len == sizeof(pj_sockaddr_in) ||
829 addr_len == sizeof(pj_sockaddr_in6), PJ_EINVAL);
830
831 attr_len = pj_sockaddr_get_addr_len(addr) + 4;
832 INIT_ATTR(attr, attr_type, attr_len);
833
834 pj_memcpy(&attr->sockaddr, addr, addr_len);
835 attr->xor_ed = xor_ed;
836
837 return PJ_SUCCESS;
838 }
839
840
841 /*
842 * Create a generic STUN IP address attribute for IPv4 address.
843 */
pj_stun_sockaddr_attr_create(pj_pool_t * pool,int attr_type,pj_bool_t xor_ed,const pj_sockaddr_t * addr,unsigned addr_len,pj_stun_sockaddr_attr ** p_attr)844 PJ_DEF(pj_status_t) pj_stun_sockaddr_attr_create(pj_pool_t *pool,
845 int attr_type,
846 pj_bool_t xor_ed,
847 const pj_sockaddr_t *addr,
848 unsigned addr_len,
849 pj_stun_sockaddr_attr **p_attr)
850 {
851 pj_stun_sockaddr_attr *attr;
852
853 PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
854 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
855 *p_attr = attr;
856 return pj_stun_sockaddr_attr_init(attr, attr_type, xor_ed,
857 addr, addr_len);
858 }
859
860
861 /*
862 * Create and add generic STUN IP address attribute to a STUN message.
863 */
pj_stun_msg_add_sockaddr_attr(pj_pool_t * pool,pj_stun_msg * msg,int attr_type,pj_bool_t xor_ed,const pj_sockaddr_t * addr,unsigned addr_len)864 PJ_DEF(pj_status_t) pj_stun_msg_add_sockaddr_attr(pj_pool_t *pool,
865 pj_stun_msg *msg,
866 int attr_type,
867 pj_bool_t xor_ed,
868 const pj_sockaddr_t *addr,
869 unsigned addr_len)
870 {
871 pj_stun_sockaddr_attr *attr;
872 pj_status_t status;
873
874 status = pj_stun_sockaddr_attr_create(pool, attr_type, xor_ed,
875 addr, addr_len, &attr);
876 if (status != PJ_SUCCESS)
877 return status;
878
879 return pj_stun_msg_add_attr(msg, &attr->hdr);
880 }
881
decode_sockaddr_attr(pj_pool_t * pool,const pj_uint8_t * buf,const pj_stun_msg_hdr * msghdr,void ** p_attr)882 static pj_status_t decode_sockaddr_attr(pj_pool_t *pool,
883 const pj_uint8_t *buf,
884 const pj_stun_msg_hdr *msghdr,
885 void **p_attr)
886 {
887 pj_stun_sockaddr_attr *attr;
888 int af;
889 unsigned addr_len;
890 pj_uint32_t val;
891
892 PJ_CHECK_STACK();
893
894 PJ_UNUSED_ARG(msghdr);
895
896 /* Create the attribute */
897 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
898 GETATTRHDR(buf, &attr->hdr);
899
900 /* Check that the attribute length is valid */
901 if (attr->hdr.length != STUN_GENERIC_IPV4_ADDR_LEN &&
902 attr->hdr.length != STUN_GENERIC_IPV6_ADDR_LEN)
903 {
904 return PJNATH_ESTUNINATTRLEN;
905 }
906
907 /* Check address family */
908 val = *(pj_uint8_t*)(buf + ATTR_HDR_LEN + 1);
909
910 /* Check address family is valid */
911 if (val == 1) {
912 if (attr->hdr.length != STUN_GENERIC_IPV4_ADDR_LEN)
913 return PJNATH_ESTUNINATTRLEN;
914 af = pj_AF_INET();
915 addr_len = 4;
916 } else if (val == 2) {
917 if (attr->hdr.length != STUN_GENERIC_IPV6_ADDR_LEN)
918 return PJNATH_ESTUNINATTRLEN;
919 af = pj_AF_INET6();
920 addr_len = 16;
921 } else {
922 /* Invalid address family */
923 return PJNATH_EINVAF;
924 }
925
926 /* Get port and address */
927 pj_sockaddr_init(af, &attr->sockaddr, NULL, 0);
928 pj_sockaddr_set_port(&attr->sockaddr,
929 GETVAL16H(buf, ATTR_HDR_LEN+2));
930 pj_memcpy(pj_sockaddr_get_addr(&attr->sockaddr),
931 buf+ATTR_HDR_LEN+4,
932 addr_len);
933
934 /* Done */
935 *p_attr = (void*)attr;
936
937 return PJ_SUCCESS;
938 }
939
940
decode_xored_sockaddr_attr(pj_pool_t * pool,const pj_uint8_t * buf,const pj_stun_msg_hdr * msghdr,void ** p_attr)941 static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool,
942 const pj_uint8_t *buf,
943 const pj_stun_msg_hdr *msghdr,
944 void **p_attr)
945 {
946 pj_stun_sockaddr_attr *attr;
947 pj_status_t status;
948
949 status = decode_sockaddr_attr(pool, buf, msghdr, p_attr);
950 if (status != PJ_SUCCESS)
951 return status;
952
953 attr = *(pj_stun_sockaddr_attr**)p_attr;
954
955 attr->xor_ed = PJ_TRUE;
956
957 if (attr->sockaddr.addr.sa_family == pj_AF_INET()) {
958 attr->sockaddr.ipv4.sin_port ^= pj_htons(PJ_STUN_MAGIC >> 16);
959 attr->sockaddr.ipv4.sin_addr.s_addr ^= pj_htonl(PJ_STUN_MAGIC);
960 } else if (attr->sockaddr.addr.sa_family == pj_AF_INET6()) {
961 unsigned i;
962 pj_uint8_t *dst = (pj_uint8_t*) &attr->sockaddr.ipv6.sin6_addr;
963 pj_uint32_t magic = pj_htonl(PJ_STUN_MAGIC);
964
965 attr->sockaddr.ipv6.sin6_port ^= pj_htons(PJ_STUN_MAGIC >> 16);
966
967 /* If the IP address family is IPv6, X-Address is computed by
968 * taking the mapped IP address in host byte order, XOR'ing it
969 * with the concatenation of the magic cookie and the 96-bit
970 * transaction ID, and converting the result to network byte
971 * order.
972 */
973 for (i=0; i<4; ++i) {
974 dst[i] ^= ((const pj_uint8_t*)&magic)[i];
975 }
976 pj_assert(sizeof(msghdr->tsx_id[0]) == 1);
977 for (i=0; i<12; ++i) {
978 dst[i+4] ^= msghdr->tsx_id[i];
979 }
980
981 } else {
982 return PJNATH_EINVAF;
983 }
984
985 /* Done */
986 *p_attr = attr;
987
988 return PJ_SUCCESS;
989 }
990
991
encode_sockaddr_attr(const void * a,pj_uint8_t * buf,unsigned len,const pj_stun_msg_hdr * msghdr,unsigned * printed)992 static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf,
993 unsigned len,
994 const pj_stun_msg_hdr *msghdr,
995 unsigned *printed)
996 {
997 pj_uint8_t *start_buf = buf;
998 const pj_stun_sockaddr_attr *ca =
999 (const pj_stun_sockaddr_attr *)a;
1000
1001 PJ_CHECK_STACK();
1002
1003 /* Common: attribute type */
1004 PUTVAL16H(buf, 0, ca->hdr.type);
1005
1006 if (ca->sockaddr.addr.sa_family == pj_AF_INET()) {
1007 enum {
1008 ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IPV4_ADDR_LEN
1009 };
1010
1011 if (len < ATTR_LEN)
1012 return PJ_ETOOSMALL;
1013
1014 /* attribute len */
1015 PUTVAL16H(buf, 2, STUN_GENERIC_IPV4_ADDR_LEN);
1016 buf += ATTR_HDR_LEN;
1017
1018 /* Ignored */
1019 *buf++ = '\0';
1020
1021 /* Address family, 1 for IPv4 */
1022 *buf++ = 1;
1023
1024 /* IPv4 address */
1025 if (ca->xor_ed) {
1026 pj_uint32_t addr;
1027 pj_uint16_t port;
1028
1029 addr = ca->sockaddr.ipv4.sin_addr.s_addr;
1030 port = ca->sockaddr.ipv4.sin_port;
1031
1032 port ^= pj_htons(PJ_STUN_MAGIC >> 16);
1033 addr ^= pj_htonl(PJ_STUN_MAGIC);
1034
1035 /* Port */
1036 pj_memcpy(buf, &port, 2);
1037 buf += 2;
1038
1039 /* Address */
1040 pj_memcpy(buf, &addr, 4);
1041 buf += 4;
1042
1043 } else {
1044 /* Port */
1045 pj_memcpy(buf, &ca->sockaddr.ipv4.sin_port, 2);
1046 buf += 2;
1047
1048 /* Address */
1049 pj_memcpy(buf, &ca->sockaddr.ipv4.sin_addr, 4);
1050 buf += 4;
1051 }
1052
1053 pj_assert(buf - start_buf == ATTR_LEN);
1054
1055 } else if (ca->sockaddr.addr.sa_family == pj_AF_INET6()) {
1056 /* IPv6 address */
1057 enum {
1058 ATTR_LEN = ATTR_HDR_LEN + STUN_GENERIC_IPV6_ADDR_LEN
1059 };
1060
1061 if (len < ATTR_LEN)
1062 return PJ_ETOOSMALL;
1063
1064 /* attribute len */
1065 PUTVAL16H(buf, 2, STUN_GENERIC_IPV6_ADDR_LEN);
1066 buf += ATTR_HDR_LEN;
1067
1068 /* Ignored */
1069 *buf++ = '\0';
1070
1071 /* Address family, 2 for IPv6 */
1072 *buf++ = 2;
1073
1074 /* IPv6 address */
1075 if (ca->xor_ed) {
1076 unsigned i;
1077 pj_uint8_t *dst;
1078 const pj_uint8_t *src;
1079 pj_uint32_t magic = pj_htonl(PJ_STUN_MAGIC);
1080 pj_uint16_t port = ca->sockaddr.ipv6.sin6_port;
1081
1082 /* Port */
1083 port ^= pj_htons(PJ_STUN_MAGIC >> 16);
1084 pj_memcpy(buf, &port, 2);
1085 buf += 2;
1086
1087 /* Address */
1088 dst = buf;
1089 src = (const pj_uint8_t*) &ca->sockaddr.ipv6.sin6_addr;
1090 for (i=0; i<4; ++i) {
1091 dst[i] = (pj_uint8_t)(src[i] ^ ((const pj_uint8_t*)&magic)[i]);
1092 }
1093 pj_assert(sizeof(msghdr->tsx_id[0]) == 1);
1094 for (i=0; i<12; ++i) {
1095 dst[i+4] = (pj_uint8_t)(src[i+4] ^ msghdr->tsx_id[i]);
1096 }
1097
1098 buf += 16;
1099
1100 } else {
1101 /* Port */
1102 pj_memcpy(buf, &ca->sockaddr.ipv6.sin6_port, 2);
1103 buf += 2;
1104
1105 /* Address */
1106 pj_memcpy(buf, &ca->sockaddr.ipv6.sin6_addr, 16);
1107 buf += 16;
1108 }
1109
1110 pj_assert(buf - start_buf == ATTR_LEN);
1111
1112 } else {
1113 return PJNATH_EINVAF;
1114 }
1115
1116 /* Done */
1117 *printed = (unsigned)(buf - start_buf);
1118
1119 return PJ_SUCCESS;
1120 }
1121
1122
clone_sockaddr_attr(pj_pool_t * pool,const void * src)1123 static void* clone_sockaddr_attr(pj_pool_t *pool, const void *src)
1124 {
1125 pj_stun_sockaddr_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_sockaddr_attr);
1126 pj_memcpy(dst, src, sizeof(pj_stun_sockaddr_attr));
1127 return (void*)dst;
1128 }
1129
1130 //////////////////////////////////////////////////////////////////////////////
1131 /*
1132 * STUN generic string attribute
1133 */
1134
1135 /*
1136 * Initialize a STUN generic string attribute.
1137 */
pj_stun_string_attr_init(pj_stun_string_attr * attr,pj_pool_t * pool,int attr_type,const pj_str_t * value)1138 PJ_DEF(pj_status_t) pj_stun_string_attr_init( pj_stun_string_attr *attr,
1139 pj_pool_t *pool,
1140 int attr_type,
1141 const pj_str_t *value)
1142 {
1143 if (value && value->slen) {
1144 INIT_ATTR(attr, attr_type, value->slen);
1145 attr->value.slen = value->slen;
1146 pj_strdup(pool, &attr->value, value);
1147 } else {
1148 INIT_ATTR(attr, attr_type, 0);
1149 }
1150 return PJ_SUCCESS;
1151 }
1152
1153
1154 /*
1155 * Create a STUN generic string attribute.
1156 */
pj_stun_string_attr_create(pj_pool_t * pool,int attr_type,const pj_str_t * value,pj_stun_string_attr ** p_attr)1157 PJ_DEF(pj_status_t) pj_stun_string_attr_create(pj_pool_t *pool,
1158 int attr_type,
1159 const pj_str_t *value,
1160 pj_stun_string_attr **p_attr)
1161 {
1162 pj_stun_string_attr *attr;
1163
1164 PJ_ASSERT_RETURN(pool && value && p_attr, PJ_EINVAL);
1165
1166 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_string_attr);
1167 *p_attr = attr;
1168
1169 return pj_stun_string_attr_init(attr, pool, attr_type, value);
1170 }
1171
1172
1173 /*
1174 * Create and add STUN generic string attribute to the message.
1175 */
pj_stun_msg_add_string_attr(pj_pool_t * pool,pj_stun_msg * msg,int attr_type,const pj_str_t * value)1176 PJ_DEF(pj_status_t) pj_stun_msg_add_string_attr(pj_pool_t *pool,
1177 pj_stun_msg *msg,
1178 int attr_type,
1179 const pj_str_t *value)
1180 {
1181 pj_stun_string_attr *attr = NULL;
1182 pj_status_t status;
1183
1184 status = pj_stun_string_attr_create(pool, attr_type, value,
1185 &attr);
1186 if (status != PJ_SUCCESS)
1187 return status;
1188
1189 return pj_stun_msg_add_attr(msg, &attr->hdr);
1190 }
1191
1192
decode_string_attr(pj_pool_t * pool,const pj_uint8_t * buf,const pj_stun_msg_hdr * msghdr,void ** p_attr)1193 static pj_status_t decode_string_attr(pj_pool_t *pool,
1194 const pj_uint8_t *buf,
1195 const pj_stun_msg_hdr *msghdr,
1196 void **p_attr)
1197 {
1198 pj_stun_string_attr *attr;
1199 pj_str_t value;
1200
1201 PJ_UNUSED_ARG(msghdr);
1202
1203 /* Create the attribute */
1204 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_string_attr);
1205 GETATTRHDR(buf, &attr->hdr);
1206
1207 /* Get pointer to the string in the message */
1208 value.ptr = ((char*)buf + ATTR_HDR_LEN);
1209 value.slen = attr->hdr.length;
1210
1211 /* Copy the string to the attribute */
1212 pj_strdup(pool, &attr->value, &value);
1213
1214 /* Done */
1215 *p_attr = attr;
1216
1217 return PJ_SUCCESS;
1218
1219 }
1220
1221
encode_string_attr(const void * a,pj_uint8_t * buf,unsigned len,const pj_stun_msg_hdr * msghdr,unsigned * printed)1222 static pj_status_t encode_string_attr(const void *a, pj_uint8_t *buf,
1223 unsigned len,
1224 const pj_stun_msg_hdr *msghdr,
1225 unsigned *printed)
1226 {
1227 const pj_stun_string_attr *ca =
1228 (const pj_stun_string_attr*)a;
1229
1230 PJ_CHECK_STACK();
1231
1232 PJ_UNUSED_ARG(msghdr);
1233
1234 /* Calculated total attr_len (add padding if necessary) */
1235 *printed = ((unsigned)ca->value.slen + ATTR_HDR_LEN + 3) & (~3);
1236 if (len < *printed) {
1237 *printed = 0;
1238 return PJ_ETOOSMALL;
1239 }
1240
1241 PUTVAL16H(buf, 0, ca->hdr.type);
1242
1243 /* Special treatment for SOFTWARE attribute:
1244 * This attribute had caused interop problem when talking to
1245 * legacy RFC 3489 STUN servers, due to different "length"
1246 * rules with RFC 5389.
1247 */
1248 if (msghdr->magic != PJ_STUN_MAGIC ||
1249 ca->hdr.type == PJ_STUN_ATTR_SOFTWARE)
1250 {
1251 /* Set the length to be 4-bytes aligned so that we can
1252 * communicate with RFC 3489 endpoints
1253 */
1254 PUTVAL16H(buf, 2, (pj_uint16_t)((ca->value.slen + 3) & (~3)));
1255 } else {
1256 /* Use RFC 5389 rule */
1257 PUTVAL16H(buf, 2, (pj_uint16_t)ca->value.slen);
1258 }
1259
1260 /* Copy the string */
1261 pj_memcpy(buf+ATTR_HDR_LEN, ca->value.ptr, ca->value.slen);
1262
1263 /* Add padding character, if string is not 4-bytes aligned. */
1264 if (ca->value.slen & 0x03) {
1265 pj_uint8_t pad[3];
1266 pj_memset(pad, padding_char, sizeof(pad));
1267 pj_memcpy(buf+ATTR_HDR_LEN+ca->value.slen, pad,
1268 4-(ca->value.slen & 0x03));
1269 }
1270
1271 /* Done */
1272 return PJ_SUCCESS;
1273 }
1274
1275
clone_string_attr(pj_pool_t * pool,const void * src)1276 static void* clone_string_attr(pj_pool_t *pool, const void *src)
1277 {
1278 const pj_stun_string_attr *asrc = (const pj_stun_string_attr*)src;
1279 pj_stun_string_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_string_attr);
1280
1281 pj_memcpy(dst, src, sizeof(pj_stun_attr_hdr));
1282 pj_strdup(pool, &dst->value, &asrc->value);
1283
1284 return (void*)dst;
1285 }
1286
1287 //////////////////////////////////////////////////////////////////////////////
1288 /*
1289 * STUN empty attribute (used by USE-CANDIDATE).
1290 */
1291
1292 /*
1293 * Create a STUN empty attribute.
1294 */
pj_stun_empty_attr_create(pj_pool_t * pool,int attr_type,pj_stun_empty_attr ** p_attr)1295 PJ_DEF(pj_status_t) pj_stun_empty_attr_create(pj_pool_t *pool,
1296 int attr_type,
1297 pj_stun_empty_attr **p_attr)
1298 {
1299 pj_stun_empty_attr *attr;
1300
1301 PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
1302
1303 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_empty_attr);
1304 INIT_ATTR(attr, attr_type, 0);
1305
1306 *p_attr = attr;
1307
1308 return PJ_SUCCESS;
1309 }
1310
1311
1312 /*
1313 * Create STUN empty attribute and add the attribute to the message.
1314 */
pj_stun_msg_add_empty_attr(pj_pool_t * pool,pj_stun_msg * msg,int attr_type)1315 PJ_DEF(pj_status_t) pj_stun_msg_add_empty_attr( pj_pool_t *pool,
1316 pj_stun_msg *msg,
1317 int attr_type)
1318 {
1319 pj_stun_empty_attr *attr = NULL;
1320 pj_status_t status;
1321
1322 status = pj_stun_empty_attr_create(pool, attr_type, &attr);
1323 if (status != PJ_SUCCESS)
1324 return status;
1325
1326 return pj_stun_msg_add_attr(msg, &attr->hdr);
1327 }
1328
decode_empty_attr(pj_pool_t * pool,const pj_uint8_t * buf,const pj_stun_msg_hdr * msghdr,void ** p_attr)1329 static pj_status_t decode_empty_attr(pj_pool_t *pool,
1330 const pj_uint8_t *buf,
1331 const pj_stun_msg_hdr *msghdr,
1332 void **p_attr)
1333 {
1334 pj_stun_empty_attr *attr;
1335
1336 PJ_UNUSED_ARG(msghdr);
1337
1338 /* Check that the struct address is valid */
1339 pj_assert(sizeof(pj_stun_empty_attr) == ATTR_HDR_LEN);
1340
1341 /* Create the attribute */
1342 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_empty_attr);
1343 GETATTRHDR(buf, &attr->hdr);
1344
1345 /* Check that the attribute length is valid */
1346 if (attr->hdr.length != 0)
1347 return PJNATH_ESTUNINATTRLEN;
1348
1349 /* Done */
1350 *p_attr = attr;
1351
1352 return PJ_SUCCESS;
1353 }
1354
1355
encode_empty_attr(const void * a,pj_uint8_t * buf,unsigned len,const pj_stun_msg_hdr * msghdr,unsigned * printed)1356 static pj_status_t encode_empty_attr(const void *a, pj_uint8_t *buf,
1357 unsigned len,
1358 const pj_stun_msg_hdr *msghdr,
1359 unsigned *printed)
1360 {
1361 const pj_stun_empty_attr *ca = (pj_stun_empty_attr*)a;
1362
1363 PJ_UNUSED_ARG(msghdr);
1364
1365 if (len < ATTR_HDR_LEN)
1366 return PJ_ETOOSMALL;
1367
1368 PUTVAL16H(buf, 0, ca->hdr.type);
1369 PUTVAL16H(buf, 2, 0);
1370
1371 /* Done */
1372 *printed = ATTR_HDR_LEN;
1373
1374 return PJ_SUCCESS;
1375 }
1376
1377
clone_empty_attr(pj_pool_t * pool,const void * src)1378 static void* clone_empty_attr(pj_pool_t *pool, const void *src)
1379 {
1380 pj_stun_empty_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_empty_attr);
1381
1382 pj_memcpy(dst, src, sizeof(pj_stun_empty_attr));
1383
1384 return (void*) dst;
1385 }
1386
1387 //////////////////////////////////////////////////////////////////////////////
1388 /*
1389 * STUN generic 32bit integer attribute.
1390 */
1391
1392 /*
1393 * Create a STUN generic 32bit value attribute.
1394 */
pj_stun_uint_attr_create(pj_pool_t * pool,int attr_type,pj_uint32_t value,pj_stun_uint_attr ** p_attr)1395 PJ_DEF(pj_status_t) pj_stun_uint_attr_create(pj_pool_t *pool,
1396 int attr_type,
1397 pj_uint32_t value,
1398 pj_stun_uint_attr **p_attr)
1399 {
1400 pj_stun_uint_attr *attr;
1401
1402 PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
1403
1404 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint_attr);
1405 INIT_ATTR(attr, attr_type, 4);
1406 attr->value = value;
1407
1408 *p_attr = attr;
1409
1410 return PJ_SUCCESS;
1411 }
1412
1413 /* Create and add STUN generic 32bit value attribute to the message. */
pj_stun_msg_add_uint_attr(pj_pool_t * pool,pj_stun_msg * msg,int attr_type,pj_uint32_t value)1414 PJ_DEF(pj_status_t) pj_stun_msg_add_uint_attr(pj_pool_t *pool,
1415 pj_stun_msg *msg,
1416 int attr_type,
1417 pj_uint32_t value)
1418 {
1419 pj_stun_uint_attr *attr = NULL;
1420 pj_status_t status;
1421
1422 status = pj_stun_uint_attr_create(pool, attr_type, value, &attr);
1423 if (status != PJ_SUCCESS)
1424 return status;
1425
1426 return pj_stun_msg_add_attr(msg, &attr->hdr);
1427 }
1428
decode_uint_attr(pj_pool_t * pool,const pj_uint8_t * buf,const pj_stun_msg_hdr * msghdr,void ** p_attr)1429 static pj_status_t decode_uint_attr(pj_pool_t *pool,
1430 const pj_uint8_t *buf,
1431 const pj_stun_msg_hdr *msghdr,
1432 void **p_attr)
1433 {
1434 pj_stun_uint_attr *attr;
1435
1436 PJ_UNUSED_ARG(msghdr);
1437
1438 /* Create the attribute */
1439 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint_attr);
1440 GETATTRHDR(buf, &attr->hdr);
1441
1442 attr->value = GETVAL32H(buf, 4);
1443
1444 /* Check that the attribute length is valid */
1445 if (attr->hdr.length != 4)
1446 return PJNATH_ESTUNINATTRLEN;
1447
1448 /* Done */
1449 *p_attr = attr;
1450
1451 return PJ_SUCCESS;
1452 }
1453
1454
encode_uint_attr(const void * a,pj_uint8_t * buf,unsigned len,const pj_stun_msg_hdr * msghdr,unsigned * printed)1455 static pj_status_t encode_uint_attr(const void *a, pj_uint8_t *buf,
1456 unsigned len,
1457 const pj_stun_msg_hdr *msghdr,
1458 unsigned *printed)
1459 {
1460 const pj_stun_uint_attr *ca = (const pj_stun_uint_attr*)a;
1461
1462 PJ_CHECK_STACK();
1463
1464 PJ_UNUSED_ARG(msghdr);
1465
1466 if (len < 8)
1467 return PJ_ETOOSMALL;
1468
1469 PUTVAL16H(buf, 0, ca->hdr.type);
1470 PUTVAL16H(buf, 2, (pj_uint16_t)4);
1471 PUTVAL32H(buf, 4, ca->value);
1472
1473 /* Done */
1474 *printed = 8;
1475
1476 return PJ_SUCCESS;
1477 }
1478
1479
clone_uint_attr(pj_pool_t * pool,const void * src)1480 static void* clone_uint_attr(pj_pool_t *pool, const void *src)
1481 {
1482 pj_stun_uint_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_uint_attr);
1483
1484 pj_memcpy(dst, src, sizeof(pj_stun_uint_attr));
1485
1486 return (void*)dst;
1487 }
1488
1489 //////////////////////////////////////////////////////////////////////////////
1490
1491 /*
1492 * Create a STUN generic 64bit value attribute.
1493 */
pj_stun_uint64_attr_create(pj_pool_t * pool,int attr_type,const pj_timestamp * value,pj_stun_uint64_attr ** p_attr)1494 PJ_DEF(pj_status_t) pj_stun_uint64_attr_create(pj_pool_t *pool,
1495 int attr_type,
1496 const pj_timestamp *value,
1497 pj_stun_uint64_attr **p_attr)
1498 {
1499 pj_stun_uint64_attr *attr;
1500
1501 PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
1502
1503 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint64_attr);
1504 INIT_ATTR(attr, attr_type, 8);
1505
1506 if (value) {
1507 attr->value.u32.hi = value->u32.hi;
1508 attr->value.u32.lo = value->u32.lo;
1509 }
1510
1511 *p_attr = attr;
1512
1513 return PJ_SUCCESS;
1514 }
1515
1516 /* Create and add STUN generic 64bit value attribute to the message. */
pj_stun_msg_add_uint64_attr(pj_pool_t * pool,pj_stun_msg * msg,int attr_type,const pj_timestamp * value)1517 PJ_DEF(pj_status_t) pj_stun_msg_add_uint64_attr(pj_pool_t *pool,
1518 pj_stun_msg *msg,
1519 int attr_type,
1520 const pj_timestamp *value)
1521 {
1522 pj_stun_uint64_attr *attr = NULL;
1523 pj_status_t status;
1524
1525 status = pj_stun_uint64_attr_create(pool, attr_type, value, &attr);
1526 if (status != PJ_SUCCESS)
1527 return status;
1528
1529 return pj_stun_msg_add_attr(msg, &attr->hdr);
1530 }
1531
decode_uint64_attr(pj_pool_t * pool,const pj_uint8_t * buf,const pj_stun_msg_hdr * msghdr,void ** p_attr)1532 static pj_status_t decode_uint64_attr(pj_pool_t *pool,
1533 const pj_uint8_t *buf,
1534 const pj_stun_msg_hdr *msghdr,
1535 void **p_attr)
1536 {
1537 pj_stun_uint64_attr *attr;
1538
1539 PJ_UNUSED_ARG(msghdr);
1540
1541 /* Create the attribute */
1542 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_uint64_attr);
1543 GETATTRHDR(buf, &attr->hdr);
1544
1545 if (attr->hdr.length != 8)
1546 return PJNATH_ESTUNINATTRLEN;
1547
1548 GETVAL64H(buf, 4, &attr->value);
1549
1550 /* Done */
1551 *p_attr = attr;
1552
1553 return PJ_SUCCESS;
1554 }
1555
1556
encode_uint64_attr(const void * a,pj_uint8_t * buf,unsigned len,const pj_stun_msg_hdr * msghdr,unsigned * printed)1557 static pj_status_t encode_uint64_attr(const void *a, pj_uint8_t *buf,
1558 unsigned len,
1559 const pj_stun_msg_hdr *msghdr,
1560 unsigned *printed)
1561 {
1562 const pj_stun_uint64_attr *ca = (const pj_stun_uint64_attr*)a;
1563
1564 PJ_CHECK_STACK();
1565
1566 PJ_UNUSED_ARG(msghdr);
1567
1568 if (len < 12)
1569 return PJ_ETOOSMALL;
1570
1571 PUTVAL16H(buf, 0, ca->hdr.type);
1572 PUTVAL16H(buf, 2, (pj_uint16_t)8);
1573 PUTVAL64H(buf, 4, &ca->value);
1574
1575 /* Done */
1576 *printed = 12;
1577
1578 return PJ_SUCCESS;
1579 }
1580
1581
clone_uint64_attr(pj_pool_t * pool,const void * src)1582 static void* clone_uint64_attr(pj_pool_t *pool, const void *src)
1583 {
1584 pj_stun_uint64_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_uint64_attr);
1585
1586 pj_memcpy(dst, src, sizeof(pj_stun_uint64_attr));
1587
1588 return (void*)dst;
1589 }
1590
1591
1592 //////////////////////////////////////////////////////////////////////////////
1593 /*
1594 * STUN MESSAGE-INTEGRITY attribute.
1595 */
1596
1597 /*
1598 * Create a STUN MESSAGE-INTEGRITY attribute.
1599 */
pj_stun_msgint_attr_create(pj_pool_t * pool,pj_stun_msgint_attr ** p_attr)1600 PJ_DEF(pj_status_t) pj_stun_msgint_attr_create(pj_pool_t *pool,
1601 pj_stun_msgint_attr **p_attr)
1602 {
1603 pj_stun_msgint_attr *attr;
1604
1605 PJ_ASSERT_RETURN(pool && p_attr, PJ_EINVAL);
1606
1607 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_msgint_attr);
1608 INIT_ATTR(attr, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 20);
1609
1610 *p_attr = attr;
1611
1612 return PJ_SUCCESS;
1613 }
1614
1615
pj_stun_msg_add_msgint_attr(pj_pool_t * pool,pj_stun_msg * msg)1616 PJ_DEF(pj_status_t) pj_stun_msg_add_msgint_attr(pj_pool_t *pool,
1617 pj_stun_msg *msg)
1618 {
1619 pj_stun_msgint_attr *attr = NULL;
1620 pj_status_t status;
1621
1622 status = pj_stun_msgint_attr_create(pool, &attr);
1623 if (status != PJ_SUCCESS)
1624 return status;
1625
1626 return pj_stun_msg_add_attr(msg, &attr->hdr);
1627 }
1628
decode_msgint_attr(pj_pool_t * pool,const pj_uint8_t * buf,const pj_stun_msg_hdr * msghdr,void ** p_attr)1629 static pj_status_t decode_msgint_attr(pj_pool_t *pool,
1630 const pj_uint8_t *buf,
1631 const pj_stun_msg_hdr *msghdr,
1632 void **p_attr)
1633 {
1634 pj_stun_msgint_attr *attr;
1635
1636 PJ_UNUSED_ARG(msghdr);
1637
1638 /* Create attribute */
1639 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_msgint_attr);
1640 GETATTRHDR(buf, &attr->hdr);
1641
1642 /* Check that the attribute length is valid */
1643 if (attr->hdr.length != 20)
1644 return PJNATH_ESTUNINATTRLEN;
1645
1646 /* Copy hmac */
1647 pj_memcpy(attr->hmac, buf+4, 20);
1648
1649 /* Done */
1650 *p_attr = attr;
1651 return PJ_SUCCESS;
1652 }
1653
1654
encode_msgint_attr(const void * a,pj_uint8_t * buf,unsigned len,const pj_stun_msg_hdr * msghdr,unsigned * printed)1655 static pj_status_t encode_msgint_attr(const void *a, pj_uint8_t *buf,
1656 unsigned len,
1657 const pj_stun_msg_hdr *msghdr,
1658 unsigned *printed)
1659 {
1660 const pj_stun_msgint_attr *ca = (const pj_stun_msgint_attr*)a;
1661
1662 PJ_CHECK_STACK();
1663
1664 PJ_UNUSED_ARG(msghdr);
1665
1666 if (len < 24)
1667 return PJ_ETOOSMALL;
1668
1669 /* Copy and convert attribute to network byte order */
1670 PUTVAL16H(buf, 0, ca->hdr.type);
1671 PUTVAL16H(buf, 2, ca->hdr.length);
1672
1673 pj_memcpy(buf+4, ca->hmac, 20);
1674
1675 /* Done */
1676 *printed = 24;
1677
1678 return PJ_SUCCESS;
1679 }
1680
1681
clone_msgint_attr(pj_pool_t * pool,const void * src)1682 static void* clone_msgint_attr(pj_pool_t *pool, const void *src)
1683 {
1684 pj_stun_msgint_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_msgint_attr);
1685
1686 pj_memcpy(dst, src, sizeof(pj_stun_msgint_attr));
1687
1688 return (void*) dst;
1689 }
1690
1691 //////////////////////////////////////////////////////////////////////////////
1692 /*
1693 * STUN ERROR-CODE
1694 */
1695
1696 /*
1697 * Create a STUN ERROR-CODE attribute.
1698 */
pj_stun_errcode_attr_create(pj_pool_t * pool,int err_code,const pj_str_t * err_reason,pj_stun_errcode_attr ** p_attr)1699 PJ_DEF(pj_status_t) pj_stun_errcode_attr_create(pj_pool_t *pool,
1700 int err_code,
1701 const pj_str_t *err_reason,
1702 pj_stun_errcode_attr **p_attr)
1703 {
1704 pj_stun_errcode_attr *attr;
1705 char err_buf[80];
1706 pj_str_t str;
1707
1708 PJ_ASSERT_RETURN(pool && err_code && p_attr, PJ_EINVAL);
1709
1710 if (err_reason == NULL) {
1711 str = pj_stun_get_err_reason(err_code);
1712 if (str.slen == 0) {
1713 str.slen = pj_ansi_snprintf(err_buf, sizeof(err_buf),
1714 "Unknown error %d", err_code);
1715 str.ptr = err_buf;
1716 }
1717 err_reason = &str;
1718 }
1719
1720 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_errcode_attr);
1721 INIT_ATTR(attr, PJ_STUN_ATTR_ERROR_CODE, 4+err_reason->slen);
1722 attr->err_code = err_code;
1723 pj_strdup(pool, &attr->reason, err_reason);
1724
1725 *p_attr = attr;
1726
1727 return PJ_SUCCESS;
1728 }
1729
1730
pj_stun_msg_add_errcode_attr(pj_pool_t * pool,pj_stun_msg * msg,int err_code,const pj_str_t * err_reason)1731 PJ_DEF(pj_status_t) pj_stun_msg_add_errcode_attr(pj_pool_t *pool,
1732 pj_stun_msg *msg,
1733 int err_code,
1734 const pj_str_t *err_reason)
1735 {
1736 pj_stun_errcode_attr *err_attr = NULL;
1737 pj_status_t status;
1738
1739 status = pj_stun_errcode_attr_create(pool, err_code, err_reason,
1740 &err_attr);
1741 if (status != PJ_SUCCESS)
1742 return status;
1743
1744 return pj_stun_msg_add_attr(msg, &err_attr->hdr);
1745 }
1746
decode_errcode_attr(pj_pool_t * pool,const pj_uint8_t * buf,const pj_stun_msg_hdr * msghdr,void ** p_attr)1747 static pj_status_t decode_errcode_attr(pj_pool_t *pool,
1748 const pj_uint8_t *buf,
1749 const pj_stun_msg_hdr *msghdr,
1750 void **p_attr)
1751 {
1752 pj_stun_errcode_attr *attr;
1753 pj_str_t value;
1754
1755 PJ_UNUSED_ARG(msghdr);
1756
1757 /* Create the attribute */
1758 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_errcode_attr);
1759 GETATTRHDR(buf, &attr->hdr);
1760
1761 attr->err_code = buf[6] * 100 + buf[7];
1762
1763 /* Get pointer to the string in the message */
1764 value.ptr = ((char*)buf + ATTR_HDR_LEN + 4);
1765 value.slen = attr->hdr.length - 4;
1766
1767 /* Copy the string to the attribute */
1768 pj_strdup(pool, &attr->reason, &value);
1769
1770 /* Done */
1771 *p_attr = attr;
1772
1773 return PJ_SUCCESS;
1774 }
1775
1776
encode_errcode_attr(const void * a,pj_uint8_t * buf,unsigned len,const pj_stun_msg_hdr * msghdr,unsigned * printed)1777 static pj_status_t encode_errcode_attr(const void *a, pj_uint8_t *buf,
1778 unsigned len,
1779 const pj_stun_msg_hdr *msghdr,
1780 unsigned *printed)
1781 {
1782 const pj_stun_errcode_attr *ca =
1783 (const pj_stun_errcode_attr*)a;
1784
1785 PJ_CHECK_STACK();
1786
1787 PJ_UNUSED_ARG(msghdr);
1788
1789 if (len < ATTR_HDR_LEN + 4 + (unsigned)ca->reason.slen)
1790 return PJ_ETOOSMALL;
1791
1792 /* Copy and convert attribute to network byte order */
1793 PUTVAL16H(buf, 0, ca->hdr.type);
1794 PUTVAL16H(buf, 2, (pj_uint16_t)(4 + ca->reason.slen));
1795 PUTVAL16H(buf, 4, 0);
1796 buf[6] = (pj_uint8_t)(ca->err_code / 100);
1797 buf[7] = (pj_uint8_t)(ca->err_code % 100);
1798
1799 /* Copy error string */
1800 pj_memcpy(buf + ATTR_HDR_LEN + 4, ca->reason.ptr, ca->reason.slen);
1801
1802 /* Done */
1803 *printed = (ATTR_HDR_LEN + 4 + (unsigned)ca->reason.slen + 3) & (~3);
1804
1805 return PJ_SUCCESS;
1806 }
1807
1808
clone_errcode_attr(pj_pool_t * pool,const void * src)1809 static void* clone_errcode_attr(pj_pool_t *pool, const void *src)
1810 {
1811 const pj_stun_errcode_attr *asrc = (const pj_stun_errcode_attr*)src;
1812 pj_stun_errcode_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_errcode_attr);
1813
1814 pj_memcpy(dst, src, sizeof(pj_stun_errcode_attr));
1815 pj_strdup(pool, &dst->reason, &asrc->reason);
1816
1817 return (void*)dst;
1818 }
1819
1820 //////////////////////////////////////////////////////////////////////////////
1821 /*
1822 * STUN UNKNOWN-ATTRIBUTES attribute
1823 */
1824
1825 /*
1826 * Create an empty instance of STUN UNKNOWN-ATTRIBUTES attribute.
1827 *
1828 * @param pool The pool to allocate memory from.
1829 * @param p_attr Pointer to receive the attribute.
1830 *
1831 * @return PJ_SUCCESS on success or the appropriate error code.
1832 */
pj_stun_unknown_attr_create(pj_pool_t * pool,unsigned attr_cnt,const pj_uint16_t attr_array[],pj_stun_unknown_attr ** p_attr)1833 PJ_DEF(pj_status_t) pj_stun_unknown_attr_create(pj_pool_t *pool,
1834 unsigned attr_cnt,
1835 const pj_uint16_t attr_array[],
1836 pj_stun_unknown_attr **p_attr)
1837 {
1838 pj_stun_unknown_attr *attr;
1839 unsigned i;
1840
1841 PJ_ASSERT_RETURN(pool && attr_cnt < PJ_STUN_MAX_ATTR && p_attr, PJ_EINVAL);
1842
1843 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_unknown_attr);
1844 INIT_ATTR(attr, PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES, attr_cnt * 2);
1845
1846 attr->attr_count = attr_cnt;
1847 for (i=0; i<attr_cnt; ++i) {
1848 attr->attrs[i] = attr_array[i];
1849 }
1850
1851 /* If the number of unknown attributes is an odd number, one of the
1852 * attributes MUST be repeated in the list.
1853 */
1854 /* No longer necessary
1855 if ((attr_cnt & 0x01)) {
1856 attr->attrs[attr_cnt] = attr_array[attr_cnt-1];
1857 }
1858 */
1859
1860 *p_attr = attr;
1861
1862 return PJ_SUCCESS;
1863 }
1864
1865
1866 /* Create and add STUN UNKNOWN-ATTRIBUTES attribute to the message. */
pj_stun_msg_add_unknown_attr(pj_pool_t * pool,pj_stun_msg * msg,unsigned attr_cnt,const pj_uint16_t attr_type[])1867 PJ_DEF(pj_status_t) pj_stun_msg_add_unknown_attr(pj_pool_t *pool,
1868 pj_stun_msg *msg,
1869 unsigned attr_cnt,
1870 const pj_uint16_t attr_type[])
1871 {
1872 pj_stun_unknown_attr *attr = NULL;
1873 pj_status_t status;
1874
1875 status = pj_stun_unknown_attr_create(pool, attr_cnt, attr_type, &attr);
1876 if (status != PJ_SUCCESS)
1877 return status;
1878
1879 return pj_stun_msg_add_attr(msg, &attr->hdr);
1880 }
1881
decode_unknown_attr(pj_pool_t * pool,const pj_uint8_t * buf,const pj_stun_msg_hdr * msghdr,void ** p_attr)1882 static pj_status_t decode_unknown_attr(pj_pool_t *pool,
1883 const pj_uint8_t *buf,
1884 const pj_stun_msg_hdr *msghdr,
1885 void **p_attr)
1886 {
1887 pj_stun_unknown_attr *attr;
1888 const pj_uint16_t *punk_attr;
1889 unsigned i;
1890
1891 PJ_UNUSED_ARG(msghdr);
1892
1893 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_unknown_attr);
1894 GETATTRHDR(buf, &attr->hdr);
1895
1896 attr->attr_count = (attr->hdr.length >> 1);
1897 if (attr->attr_count > PJ_STUN_MAX_ATTR)
1898 return PJ_ETOOMANY;
1899
1900 punk_attr = (const pj_uint16_t*)(buf + ATTR_HDR_LEN);
1901 for (i=0; i<attr->attr_count; ++i) {
1902 attr->attrs[i] = pj_ntohs(punk_attr[i]);
1903 }
1904
1905 /* Done */
1906 *p_attr = attr;
1907
1908 return PJ_SUCCESS;
1909 }
1910
1911
encode_unknown_attr(const void * a,pj_uint8_t * buf,unsigned len,const pj_stun_msg_hdr * msghdr,unsigned * printed)1912 static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
1913 unsigned len,
1914 const pj_stun_msg_hdr *msghdr,
1915 unsigned *printed)
1916 {
1917 const pj_stun_unknown_attr *ca = (const pj_stun_unknown_attr*) a;
1918 pj_uint16_t *dst_unk_attr;
1919 unsigned i;
1920
1921 PJ_CHECK_STACK();
1922
1923 PJ_UNUSED_ARG(msghdr);
1924
1925 /* Check that buffer is enough */
1926 if (len < ATTR_HDR_LEN + (ca->attr_count << 1))
1927 return PJ_ETOOSMALL;
1928
1929 PUTVAL16H(buf, 0, ca->hdr.type);
1930 PUTVAL16H(buf, 2, (pj_uint16_t)(ca->attr_count << 1));
1931
1932 /* Copy individual attribute */
1933 dst_unk_attr = (pj_uint16_t*)(buf + ATTR_HDR_LEN);
1934 for (i=0; i < ca->attr_count; ++i, ++dst_unk_attr) {
1935 *dst_unk_attr = pj_htons(ca->attrs[i]);
1936 }
1937
1938 /* Done */
1939 *printed = (ATTR_HDR_LEN + (ca->attr_count << 1) + 3) & (~3);
1940
1941 return PJ_SUCCESS;
1942 }
1943
1944
clone_unknown_attr(pj_pool_t * pool,const void * src)1945 static void* clone_unknown_attr(pj_pool_t *pool, const void *src)
1946 {
1947 pj_stun_unknown_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_unknown_attr);
1948
1949 pj_memcpy(dst, src, sizeof(pj_stun_unknown_attr));
1950
1951 return (void*)dst;
1952 }
1953
1954 //////////////////////////////////////////////////////////////////////////////
1955 /*
1956 * STUN generic binary attribute
1957 */
1958
1959 /*
1960 * Initialize STUN binary attribute.
1961 */
pj_stun_binary_attr_init(pj_stun_binary_attr * attr,pj_pool_t * pool,int attr_type,const pj_uint8_t * data,unsigned length)1962 PJ_DEF(pj_status_t) pj_stun_binary_attr_init( pj_stun_binary_attr *attr,
1963 pj_pool_t *pool,
1964 int attr_type,
1965 const pj_uint8_t *data,
1966 unsigned length)
1967 {
1968 PJ_ASSERT_RETURN(attr_type, PJ_EINVAL);
1969
1970 INIT_ATTR(attr, attr_type, length);
1971
1972 attr->magic = PJ_STUN_MAGIC;
1973
1974 if (data && length) {
1975 attr->length = length;
1976 attr->data = (pj_uint8_t*) pj_pool_alloc(pool, length);
1977 pj_memcpy(attr->data, data, length);
1978 } else {
1979 attr->data = NULL;
1980 attr->length = 0;
1981 }
1982
1983 return PJ_SUCCESS;
1984 }
1985
1986
1987 /*
1988 * Create a blank binary attribute.
1989 */
pj_stun_binary_attr_create(pj_pool_t * pool,int attr_type,const pj_uint8_t * data,unsigned length,pj_stun_binary_attr ** p_attr)1990 PJ_DEF(pj_status_t) pj_stun_binary_attr_create(pj_pool_t *pool,
1991 int attr_type,
1992 const pj_uint8_t *data,
1993 unsigned length,
1994 pj_stun_binary_attr **p_attr)
1995 {
1996 pj_stun_binary_attr *attr;
1997
1998 PJ_ASSERT_RETURN(pool && attr_type && p_attr, PJ_EINVAL);
1999 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_binary_attr);
2000 *p_attr = attr;
2001 return pj_stun_binary_attr_init(attr, pool, attr_type, data, length);
2002 }
2003
2004
2005 /* Create and add binary attr. */
pj_stun_msg_add_binary_attr(pj_pool_t * pool,pj_stun_msg * msg,int attr_type,const pj_uint8_t * data,unsigned length)2006 PJ_DEF(pj_status_t) pj_stun_msg_add_binary_attr(pj_pool_t *pool,
2007 pj_stun_msg *msg,
2008 int attr_type,
2009 const pj_uint8_t *data,
2010 unsigned length)
2011 {
2012 pj_stun_binary_attr *attr = NULL;
2013 pj_status_t status;
2014
2015 status = pj_stun_binary_attr_create(pool, attr_type,
2016 data, length, &attr);
2017 if (status != PJ_SUCCESS)
2018 return status;
2019
2020 return pj_stun_msg_add_attr(msg, &attr->hdr);
2021 }
2022
2023
decode_binary_attr(pj_pool_t * pool,const pj_uint8_t * buf,const pj_stun_msg_hdr * msghdr,void ** p_attr)2024 static pj_status_t decode_binary_attr(pj_pool_t *pool,
2025 const pj_uint8_t *buf,
2026 const pj_stun_msg_hdr *msghdr,
2027 void **p_attr)
2028 {
2029 pj_stun_binary_attr *attr;
2030
2031 PJ_UNUSED_ARG(msghdr);
2032
2033 /* Create the attribute */
2034 attr = PJ_POOL_ZALLOC_T(pool, pj_stun_binary_attr);
2035 GETATTRHDR(buf, &attr->hdr);
2036
2037 /* Copy the data to the attribute */
2038 attr->length = attr->hdr.length;
2039 attr->data = (pj_uint8_t*) pj_pool_alloc(pool, attr->length);
2040 pj_memcpy(attr->data, buf+ATTR_HDR_LEN, attr->length);
2041
2042 /* Done */
2043 *p_attr = attr;
2044
2045 return PJ_SUCCESS;
2046
2047 }
2048
2049
encode_binary_attr(const void * a,pj_uint8_t * buf,unsigned len,const pj_stun_msg_hdr * msghdr,unsigned * printed)2050 static pj_status_t encode_binary_attr(const void *a, pj_uint8_t *buf,
2051 unsigned len,
2052 const pj_stun_msg_hdr *msghdr,
2053 unsigned *printed)
2054 {
2055 const pj_stun_binary_attr *ca = (const pj_stun_binary_attr*)a;
2056
2057 PJ_CHECK_STACK();
2058
2059 PJ_UNUSED_ARG(msghdr);
2060
2061 /* Calculated total attr_len (add padding if necessary) */
2062 *printed = (ca->length + ATTR_HDR_LEN + 3) & (~3);
2063 if (len < *printed)
2064 return PJ_ETOOSMALL;
2065
2066 PUTVAL16H(buf, 0, ca->hdr.type);
2067 PUTVAL16H(buf, 2, (pj_uint16_t) ca->length);
2068
2069 /* Copy the data */
2070 pj_memcpy(buf+ATTR_HDR_LEN, ca->data, ca->length);
2071
2072 /* Done */
2073 return PJ_SUCCESS;
2074 }
2075
2076
clone_binary_attr(pj_pool_t * pool,const void * src)2077 static void* clone_binary_attr(pj_pool_t *pool, const void *src)
2078 {
2079 const pj_stun_binary_attr *asrc = (const pj_stun_binary_attr*)src;
2080 pj_stun_binary_attr *dst = PJ_POOL_ALLOC_T(pool, pj_stun_binary_attr);
2081
2082 pj_memcpy(dst, src, sizeof(pj_stun_binary_attr));
2083
2084 if (asrc->length) {
2085 dst->data = (pj_uint8_t*) pj_pool_alloc(pool, asrc->length);
2086 pj_memcpy(dst->data, asrc->data, asrc->length);
2087 }
2088
2089 return (void*)dst;
2090 }
2091
2092 //////////////////////////////////////////////////////////////////////////////
2093
2094 /*
2095 * Initialize a generic STUN message.
2096 */
pj_stun_msg_init(pj_stun_msg * msg,unsigned msg_type,pj_uint32_t magic,const pj_uint8_t tsx_id[12])2097 PJ_DEF(pj_status_t) pj_stun_msg_init( pj_stun_msg *msg,
2098 unsigned msg_type,
2099 pj_uint32_t magic,
2100 const pj_uint8_t tsx_id[12])
2101 {
2102 PJ_ASSERT_RETURN(msg && msg_type, PJ_EINVAL);
2103
2104 msg->hdr.type = (pj_uint16_t) msg_type;
2105 msg->hdr.length = 0;
2106 msg->hdr.magic = magic;
2107 msg->attr_count = 0;
2108
2109 if (tsx_id) {
2110 pj_memcpy(&msg->hdr.tsx_id, tsx_id, sizeof(msg->hdr.tsx_id));
2111 } else {
2112 struct transaction_id
2113 {
2114 pj_uint32_t proc_id;
2115 pj_uint32_t random;
2116 pj_uint32_t counter;
2117 } id;
2118 static pj_uint32_t pj_stun_tsx_id_counter;
2119
2120 if (!pj_stun_tsx_id_counter)
2121 pj_stun_tsx_id_counter = pj_rand();
2122
2123 id.proc_id = pj_getpid();
2124 id.random = pj_rand();
2125 id.counter = pj_stun_tsx_id_counter++;
2126
2127 pj_memcpy(&msg->hdr.tsx_id, &id, sizeof(msg->hdr.tsx_id));
2128 }
2129
2130 return PJ_SUCCESS;
2131 }
2132
2133
2134 /*
2135 * Create a blank STUN message.
2136 */
pj_stun_msg_create(pj_pool_t * pool,unsigned msg_type,pj_uint32_t magic,const pj_uint8_t tsx_id[12],pj_stun_msg ** p_msg)2137 PJ_DEF(pj_status_t) pj_stun_msg_create( pj_pool_t *pool,
2138 unsigned msg_type,
2139 pj_uint32_t magic,
2140 const pj_uint8_t tsx_id[12],
2141 pj_stun_msg **p_msg)
2142 {
2143 pj_stun_msg *msg;
2144
2145 PJ_ASSERT_RETURN(pool && msg_type && p_msg, PJ_EINVAL);
2146
2147 msg = PJ_POOL_ZALLOC_T(pool, pj_stun_msg);
2148 *p_msg = msg;
2149 return pj_stun_msg_init(msg, msg_type, magic, tsx_id);
2150 }
2151
2152
2153 /*
2154 * Clone a STUN message with all of its attributes.
2155 */
pj_stun_msg_clone(pj_pool_t * pool,const pj_stun_msg * src)2156 PJ_DEF(pj_stun_msg*) pj_stun_msg_clone( pj_pool_t *pool,
2157 const pj_stun_msg *src)
2158 {
2159 pj_stun_msg *dst;
2160 unsigned i;
2161
2162 PJ_ASSERT_RETURN(pool && src, NULL);
2163
2164 dst = PJ_POOL_ZALLOC_T(pool, pj_stun_msg);
2165 pj_memcpy(dst, src, sizeof(pj_stun_msg));
2166
2167 /* Duplicate the attributes */
2168 for (i=0, dst->attr_count=0; i<src->attr_count; ++i) {
2169 dst->attr[dst->attr_count] = pj_stun_attr_clone(pool, src->attr[i]);
2170 if (dst->attr[dst->attr_count])
2171 ++dst->attr_count;
2172 }
2173
2174 return dst;
2175 }
2176
2177
2178 /*
2179 * Add STUN attribute to STUN message.
2180 */
pj_stun_msg_add_attr(pj_stun_msg * msg,pj_stun_attr_hdr * attr)2181 PJ_DEF(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg,
2182 pj_stun_attr_hdr *attr)
2183 {
2184 PJ_ASSERT_RETURN(msg && attr, PJ_EINVAL);
2185 PJ_ASSERT_RETURN(msg->attr_count < PJ_STUN_MAX_ATTR, PJ_ETOOMANY);
2186
2187 msg->attr[msg->attr_count++] = attr;
2188 return PJ_SUCCESS;
2189 }
2190
2191
2192 /*
2193 * Check that the PDU is potentially a valid STUN message.
2194 */
pj_stun_msg_check(const pj_uint8_t * pdu,pj_size_t pdu_len,unsigned options)2195 PJ_DEF(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, pj_size_t pdu_len,
2196 unsigned options)
2197 {
2198 pj_uint32_t msg_len;
2199
2200 PJ_ASSERT_RETURN(pdu, PJ_EINVAL);
2201
2202 if (pdu_len < sizeof(pj_stun_msg_hdr))
2203 return PJNATH_EINSTUNMSGLEN;
2204
2205 /* First byte of STUN message is always 0x00 or 0x01. */
2206 if (*pdu != 0x00 && *pdu != 0x01)
2207 return PJNATH_EINSTUNMSGTYPE;
2208
2209 /* Check the PDU length */
2210 msg_len = GETVAL16H(pdu, 2);
2211 if ((msg_len + 20 > pdu_len) ||
2212 ((options & PJ_STUN_IS_DATAGRAM) && msg_len + 20 != pdu_len))
2213 {
2214 return PJNATH_EINSTUNMSGLEN;
2215 }
2216
2217 /* STUN message is always padded to the nearest 4 bytes, thus
2218 * the last two bits of the length field are always zero.
2219 */
2220 if ((msg_len & 0x03) != 0) {
2221 return PJNATH_EINSTUNMSGLEN;
2222 }
2223
2224 /* If magic is set, then there is great possibility that this is
2225 * a STUN message.
2226 */
2227 if (GETVAL32H(pdu, 4) == PJ_STUN_MAGIC) {
2228
2229 /* Check if FINGERPRINT attribute is present */
2230 if ((options & PJ_STUN_NO_FINGERPRINT_CHECK )==0 &&
2231 GETVAL16H(pdu, msg_len + 20 - 8) == PJ_STUN_ATTR_FINGERPRINT)
2232 {
2233 pj_uint16_t attr_len = GETVAL16H(pdu, msg_len + 20 - 8 + 2);
2234 pj_uint32_t fingerprint = GETVAL32H(pdu, msg_len + 20 - 8 + 4);
2235 pj_uint32_t crc;
2236
2237 if (attr_len != 4)
2238 return PJNATH_ESTUNINATTRLEN;
2239
2240 crc = pj_crc32_calc(pdu, msg_len + 20 - 8);
2241 crc ^= STUN_XOR_FINGERPRINT;
2242
2243 if (crc != fingerprint)
2244 return PJNATH_ESTUNFINGERPRINT;
2245 }
2246 }
2247
2248 /* Could be a STUN message */
2249 return PJ_SUCCESS;
2250 }
2251
2252
2253 /* Create error response */
pj_stun_msg_create_response(pj_pool_t * pool,const pj_stun_msg * req_msg,unsigned err_code,const pj_str_t * err_msg,pj_stun_msg ** p_response)2254 PJ_DEF(pj_status_t) pj_stun_msg_create_response(pj_pool_t *pool,
2255 const pj_stun_msg *req_msg,
2256 unsigned err_code,
2257 const pj_str_t *err_msg,
2258 pj_stun_msg **p_response)
2259 {
2260 unsigned msg_type = req_msg->hdr.type;
2261 pj_stun_msg *response = NULL;
2262 pj_status_t status;
2263
2264 PJ_ASSERT_RETURN(pool && p_response, PJ_EINVAL);
2265
2266 PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(msg_type),
2267 PJNATH_EINSTUNMSGTYPE);
2268
2269 /* Create response or error response */
2270 if (err_code)
2271 msg_type |= PJ_STUN_ERROR_RESPONSE_BIT;
2272 else
2273 msg_type |= PJ_STUN_SUCCESS_RESPONSE_BIT;
2274
2275 status = pj_stun_msg_create(pool, msg_type, req_msg->hdr.magic,
2276 req_msg->hdr.tsx_id, &response);
2277 if (status != PJ_SUCCESS) {
2278 return status;
2279 }
2280
2281 /* Add error code attribute */
2282 if (err_code) {
2283 status = pj_stun_msg_add_errcode_attr(pool, response,
2284 err_code, err_msg);
2285 if (status != PJ_SUCCESS) {
2286 return status;
2287 }
2288 }
2289
2290 *p_response = response;
2291 return PJ_SUCCESS;
2292 }
2293
2294
2295 /*
2296 * Parse incoming packet into STUN message.
2297 */
pj_stun_msg_decode(pj_pool_t * pool,const pj_uint8_t * pdu,pj_size_t pdu_len,unsigned options,pj_stun_msg ** p_msg,pj_size_t * p_parsed_len,pj_stun_msg ** p_response)2298 PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
2299 const pj_uint8_t *pdu,
2300 pj_size_t pdu_len,
2301 unsigned options,
2302 pj_stun_msg **p_msg,
2303 pj_size_t *p_parsed_len,
2304 pj_stun_msg **p_response)
2305 {
2306
2307 pj_stun_msg *msg;
2308 const pj_uint8_t *start_pdu = pdu;
2309 pj_bool_t has_msg_int = PJ_FALSE;
2310 pj_bool_t has_fingerprint = PJ_FALSE;
2311 pj_status_t status;
2312
2313 PJ_UNUSED_ARG(options);
2314
2315 PJ_ASSERT_RETURN(pool && pdu && pdu_len && p_msg, PJ_EINVAL);
2316 PJ_ASSERT_RETURN(sizeof(pj_stun_msg_hdr) == 20, PJ_EBUG);
2317
2318 if (p_parsed_len)
2319 *p_parsed_len = 0;
2320 if (p_response)
2321 *p_response = NULL;
2322
2323 /* Check if this is a STUN message, if necessary */
2324 if (options & PJ_STUN_CHECK_PACKET) {
2325 status = pj_stun_msg_check(pdu, pdu_len, options);
2326 if (status != PJ_SUCCESS)
2327 return status;
2328 }
2329
2330 /* Create the message, copy the header, and convert to host byte order */
2331 msg = PJ_POOL_ZALLOC_T(pool, pj_stun_msg);
2332 pj_memcpy(&msg->hdr, pdu, sizeof(pj_stun_msg_hdr));
2333 msg->hdr.type = pj_ntohs(msg->hdr.type);
2334 msg->hdr.length = pj_ntohs(msg->hdr.length);
2335 msg->hdr.magic = pj_ntohl(msg->hdr.magic);
2336
2337 pdu += sizeof(pj_stun_msg_hdr);
2338 /* pdu_len -= sizeof(pj_stun_msg_hdr); */
2339 pdu_len = msg->hdr.length;
2340
2341 /* No need to create response if this is not a request */
2342 if (!PJ_STUN_IS_REQUEST(msg->hdr.type))
2343 p_response = NULL;
2344
2345 /* Parse attributes */
2346 while (pdu_len >= 4) {
2347 unsigned attr_type, attr_val_len;
2348 const struct attr_desc *adesc;
2349
2350 /* Get attribute type and length. If length is not aligned
2351 * to 4 bytes boundary, add padding.
2352 */
2353 attr_type = GETVAL16H(pdu, 0);
2354 attr_val_len = GETVAL16H(pdu, 2);
2355 attr_val_len = (attr_val_len + 3) & (~3);
2356
2357 /* Check length */
2358 if (pdu_len < attr_val_len) {
2359 pj_str_t err_msg;
2360 char err_msg_buf[80];
2361
2362 err_msg.ptr = err_msg_buf;
2363 err_msg.slen = pj_ansi_snprintf(err_msg_buf, sizeof(err_msg_buf),
2364 "Attribute %s has invalid length",
2365 pj_stun_get_attr_name(attr_type));
2366
2367 PJ_LOG(4,(THIS_FILE, "Error decoding message: %.*s",
2368 (int)err_msg.slen, err_msg.ptr));
2369
2370 if (p_response) {
2371 pj_stun_msg_create_response(pool, msg,
2372 PJ_STUN_SC_BAD_REQUEST,
2373 &err_msg, p_response);
2374 }
2375 return PJNATH_ESTUNINATTRLEN;
2376 }
2377
2378 /* Get the attribute descriptor */
2379 adesc = find_attr_desc(attr_type);
2380
2381 if (adesc == NULL) {
2382 /* Unrecognized attribute */
2383 pj_stun_binary_attr *attr = NULL;
2384
2385 PJ_LOG(5,(THIS_FILE, "Unrecognized attribute type 0x%x",
2386 attr_type));
2387
2388 /* Is this a fatal condition? */
2389 if (attr_type <= 0x7FFF) {
2390 /* This is a mandatory attribute, we must return error
2391 * if we don't understand the attribute.
2392 */
2393 if (p_response) {
2394 unsigned err_code = PJ_STUN_SC_UNKNOWN_ATTRIBUTE;
2395
2396 status = pj_stun_msg_create_response(pool, msg,
2397 err_code, NULL,
2398 p_response);
2399 if (status==PJ_SUCCESS) {
2400 pj_uint16_t d = (pj_uint16_t)attr_type;
2401 pj_stun_msg_add_unknown_attr(pool, *p_response, 1, &d);
2402 }
2403 }
2404
2405 return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNKNOWN_ATTRIBUTE);
2406 }
2407
2408 /* Make sure we have rooms for the new attribute */
2409 if (msg->attr_count >= PJ_STUN_MAX_ATTR) {
2410 if (p_response) {
2411 pj_stun_msg_create_response(pool, msg,
2412 PJ_STUN_SC_SERVER_ERROR,
2413 NULL, p_response);
2414 }
2415 return PJNATH_ESTUNTOOMANYATTR;
2416 }
2417
2418 /* Create binary attribute to represent this */
2419 status = pj_stun_binary_attr_create(pool, attr_type, pdu+4,
2420 GETVAL16H(pdu, 2), &attr);
2421 if (status != PJ_SUCCESS) {
2422 if (p_response) {
2423 pj_stun_msg_create_response(pool, msg,
2424 PJ_STUN_SC_SERVER_ERROR,
2425 NULL, p_response);
2426 }
2427
2428 PJ_LOG(4,(THIS_FILE,
2429 "Error parsing unknown STUN attribute type %d",
2430 attr_type));
2431
2432 return status;
2433 }
2434
2435 /* Add the attribute */
2436 msg->attr[msg->attr_count++] = &attr->hdr;
2437
2438 } else {
2439 void *attr;
2440 char err_msg1[PJ_ERR_MSG_SIZE],
2441 err_msg2[PJ_ERR_MSG_SIZE];
2442
2443 /* Parse the attribute */
2444 status = (adesc->decode_attr)(pool, pdu, &msg->hdr, &attr);
2445
2446 if (status != PJ_SUCCESS) {
2447 pj_strerror(status, err_msg1, sizeof(err_msg1));
2448
2449 if (p_response) {
2450 pj_str_t e;
2451
2452 e.ptr = err_msg2;
2453 e.slen= pj_ansi_snprintf(err_msg2, sizeof(err_msg2),
2454 "%s in %s",
2455 err_msg1,
2456 pj_stun_get_attr_name(attr_type));
2457 if (e.slen < 1 || e.slen >= (int)sizeof(err_msg2))
2458 e.slen = sizeof(err_msg2) - 1;
2459 pj_stun_msg_create_response(pool, msg,
2460 PJ_STUN_SC_BAD_REQUEST,
2461 &e, p_response);
2462 }
2463
2464 PJ_LOG(4,(THIS_FILE,
2465 "Error parsing STUN attribute %s: %s",
2466 pj_stun_get_attr_name(attr_type),
2467 err_msg1));
2468
2469 return status;
2470 }
2471
2472 if (attr_type == PJ_STUN_ATTR_MESSAGE_INTEGRITY &&
2473 !has_fingerprint)
2474 {
2475 if (has_msg_int) {
2476 /* Already has MESSAGE-INTEGRITY */
2477 if (p_response) {
2478 pj_stun_msg_create_response(pool, msg,
2479 PJ_STUN_SC_BAD_REQUEST,
2480 NULL, p_response);
2481 }
2482 return PJNATH_ESTUNDUPATTR;
2483 }
2484 has_msg_int = PJ_TRUE;
2485
2486 } else if (attr_type == PJ_STUN_ATTR_FINGERPRINT) {
2487 if (has_fingerprint) {
2488 /* Already has FINGERPRINT */
2489 if (p_response) {
2490 pj_stun_msg_create_response(pool, msg,
2491 PJ_STUN_SC_BAD_REQUEST,
2492 NULL, p_response);
2493 }
2494 return PJNATH_ESTUNDUPATTR;
2495 }
2496 has_fingerprint = PJ_TRUE;
2497 } else {
2498 if (has_fingerprint) {
2499 /* Another attribute is found which is not FINGERPRINT
2500 * after FINGERPRINT. Note that non-FINGERPRINT is
2501 * allowed to appear after M-I
2502 */
2503 if (p_response) {
2504 pj_stun_msg_create_response(pool, msg,
2505 PJ_STUN_SC_BAD_REQUEST,
2506 NULL, p_response);
2507 }
2508 return PJNATH_ESTUNFINGERPOS;
2509 }
2510 }
2511
2512 /* Make sure we have rooms for the new attribute */
2513 if (msg->attr_count >= PJ_STUN_MAX_ATTR) {
2514 if (p_response) {
2515 pj_stun_msg_create_response(pool, msg,
2516 PJ_STUN_SC_SERVER_ERROR,
2517 NULL, p_response);
2518 }
2519 return PJNATH_ESTUNTOOMANYATTR;
2520 }
2521
2522 /* Add the attribute */
2523 msg->attr[msg->attr_count++] = (pj_stun_attr_hdr*)attr;
2524 }
2525
2526 /* Next attribute */
2527 if (attr_val_len + 4 >= pdu_len) {
2528 pdu += pdu_len;
2529 pdu_len = 0;
2530 } else {
2531 pdu += (attr_val_len + 4);
2532 pdu_len -= (attr_val_len + 4);
2533 }
2534 }
2535
2536 if (pdu_len > 0) {
2537 /* Stray trailing bytes */
2538 PJ_LOG(4,(THIS_FILE,
2539 "Error decoding STUN message: unparsed trailing %d bytes",
2540 pdu_len));
2541 return PJNATH_EINSTUNMSGLEN;
2542 }
2543
2544 *p_msg = msg;
2545
2546 if (p_parsed_len)
2547 *p_parsed_len = (pdu - start_pdu);
2548
2549 return PJ_SUCCESS;
2550 }
2551
2552 /*
2553 static char *print_binary(const pj_uint8_t *data, unsigned data_len)
2554 {
2555 static char static_buffer[1024];
2556 char *buffer = static_buffer;
2557 unsigned length=sizeof(static_buffer), i;
2558
2559 if (length < data_len * 2 + 8)
2560 return "";
2561
2562 pj_ansi_sprintf(buffer, ", data=");
2563 buffer += 7;
2564
2565 for (i=0; i<data_len; ++i) {
2566 pj_ansi_sprintf(buffer, "%02x", (*data) & 0xFF);
2567 buffer += 2;
2568 data++;
2569 }
2570
2571 pj_ansi_sprintf(buffer, "\n");
2572 buffer++;
2573
2574 return static_buffer;
2575 }
2576 */
2577
2578 /*
2579 * Print the message structure to a buffer.
2580 */
pj_stun_msg_encode(pj_stun_msg * msg,pj_uint8_t * buf,pj_size_t buf_size,unsigned options,const pj_str_t * key,pj_size_t * p_msg_len)2581 PJ_DEF(pj_status_t) pj_stun_msg_encode(pj_stun_msg *msg,
2582 pj_uint8_t *buf, pj_size_t buf_size,
2583 unsigned options,
2584 const pj_str_t *key,
2585 pj_size_t *p_msg_len)
2586 {
2587 pj_uint8_t *start = buf;
2588 pj_stun_msgint_attr *amsgint = NULL;
2589 pj_stun_fingerprint_attr *afingerprint = NULL;
2590 unsigned printed = 0, body_len;
2591 pj_status_t status;
2592 unsigned i;
2593
2594
2595 PJ_ASSERT_RETURN(msg && buf && buf_size, PJ_EINVAL);
2596
2597 PJ_UNUSED_ARG(options);
2598 PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);
2599
2600 /* Copy the message header part and convert the header fields to
2601 * network byte order
2602 */
2603 if (buf_size < sizeof(pj_stun_msg_hdr))
2604 return PJ_ETOOSMALL;
2605
2606 PUTVAL16H(buf, 0, msg->hdr.type);
2607 PUTVAL16H(buf, 2, 0); /* length will be calculated later */
2608 PUTVAL32H(buf, 4, msg->hdr.magic);
2609 pj_memcpy(buf+8, msg->hdr.tsx_id, sizeof(msg->hdr.tsx_id));
2610
2611 buf += sizeof(pj_stun_msg_hdr);
2612 buf_size -= sizeof(pj_stun_msg_hdr);
2613
2614 /* Encode each attribute to the message */
2615 for (i=0; i<msg->attr_count; ++i) {
2616 const struct attr_desc *adesc;
2617 const pj_stun_attr_hdr *attr_hdr = msg->attr[i];
2618
2619 if (attr_hdr->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
2620 pj_assert(amsgint == NULL);
2621 amsgint = (pj_stun_msgint_attr*) attr_hdr;
2622
2623 /* Stop when encountering MESSAGE-INTEGRITY */
2624 break;
2625
2626 } else if (attr_hdr->type == PJ_STUN_ATTR_FINGERPRINT) {
2627 afingerprint = (pj_stun_fingerprint_attr*) attr_hdr;
2628 break;
2629 }
2630
2631 adesc = find_attr_desc(attr_hdr->type);
2632 if (adesc) {
2633 status = adesc->encode_attr(attr_hdr, buf, (unsigned)buf_size,
2634 &msg->hdr, &printed);
2635 } else {
2636 /* This may be a generic attribute */
2637 const pj_stun_binary_attr *bin_attr = (const pj_stun_binary_attr*)
2638 attr_hdr;
2639 PJ_ASSERT_RETURN(bin_attr->magic == PJ_STUN_MAGIC, PJ_EBUG);
2640 status = encode_binary_attr(bin_attr, buf, (unsigned)buf_size,
2641 &msg->hdr, &printed);
2642 }
2643
2644 if (status != PJ_SUCCESS)
2645 return status;
2646
2647 buf += printed;
2648 buf_size -= printed;
2649 }
2650
2651 /* We may have stopped printing attribute because we found
2652 * MESSAGE-INTEGRITY or FINGERPRINT. Scan the rest of the
2653 * attributes.
2654 */
2655 for ( ++i; i<msg->attr_count; ++i) {
2656 const pj_stun_attr_hdr *attr_hdr = msg->attr[i];
2657
2658 /* There mustn't any attribute after FINGERPRINT */
2659 PJ_ASSERT_RETURN(afingerprint == NULL, PJNATH_ESTUNFINGERPOS);
2660
2661 if (attr_hdr->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
2662 /* There mustn't be MESSAGE-INTEGRITY before */
2663 PJ_ASSERT_RETURN(amsgint == NULL,
2664 PJNATH_ESTUNMSGINTPOS);
2665 amsgint = (pj_stun_msgint_attr*) attr_hdr;
2666
2667 } else if (attr_hdr->type == PJ_STUN_ATTR_FINGERPRINT) {
2668 afingerprint = (pj_stun_fingerprint_attr*) attr_hdr;
2669 }
2670 }
2671
2672 #if PJ_STUN_OLD_STYLE_MI_FINGERPRINT
2673 /*
2674 * This is the old style MESSAGE-INTEGRITY and FINGERPRINT
2675 * calculation, used in rfc3489bis-06 and older.
2676 */
2677 /* We MUST update the message length in the header NOW before
2678 * calculating MESSAGE-INTEGRITY and FINGERPRINT.
2679 * Note that length is not including the 20 bytes header.
2680 */
2681 if (amsgint && afingerprint) {
2682 body_len = (pj_uint16_t)((buf - start) - 20 + 24 + 8);
2683 } else if (amsgint) {
2684 body_len = (pj_uint16_t)((buf - start) - 20 + 24);
2685 } else if (afingerprint) {
2686 body_len = (pj_uint16_t)((buf - start) - 20 + 8);
2687 } else {
2688 body_len = (pj_uint16_t)((buf - start) - 20);
2689 }
2690 #else
2691 /* If MESSAGE-INTEGRITY is present, include the M-I attribute
2692 * in message length before calculating M-I
2693 */
2694 if (amsgint) {
2695 body_len = (pj_uint16_t)((buf - start) - 20 + 24);
2696 } else {
2697 body_len = (pj_uint16_t)((buf - start) - 20);
2698 }
2699 #endif /* PJ_STUN_OLD_STYLE_MI_FINGERPRINT */
2700
2701 /* hdr->length = pj_htons(length); */
2702 PUTVAL16H(start, 2, (pj_uint16_t)body_len);
2703
2704 /* Calculate message integrity, if present */
2705 if (amsgint != NULL) {
2706 pj_hmac_sha1_context ctx;
2707
2708 /* Key MUST be specified */
2709 PJ_ASSERT_RETURN(key, PJ_EINVALIDOP);
2710
2711 /* MESSAGE-INTEGRITY must be the last attribute in the message, or
2712 * the last attribute before FINGERPRINT.
2713 */
2714 if (msg->attr_count>1 && i < msg->attr_count-2) {
2715 /* Should not happen for message generated by us */
2716 pj_assert(PJ_FALSE);
2717 return PJNATH_ESTUNMSGINTPOS;
2718
2719 } else if (i == msg->attr_count-2) {
2720 if (msg->attr[i+1]->type != PJ_STUN_ATTR_FINGERPRINT) {
2721 /* Should not happen for message generated by us */
2722 pj_assert(PJ_FALSE);
2723 return PJNATH_ESTUNMSGINTPOS;
2724 } else {
2725 afingerprint = (pj_stun_fingerprint_attr*) msg->attr[i+1];
2726 }
2727 }
2728
2729 /* Calculate HMAC-SHA1 digest, add zero padding to input
2730 * if necessary to make the input 64 bytes aligned.
2731 */
2732 pj_hmac_sha1_init(&ctx, (const pj_uint8_t*)key->ptr,
2733 (unsigned)key->slen);
2734 pj_hmac_sha1_update(&ctx, (const pj_uint8_t*)start,
2735 (unsigned)(buf-start));
2736 #if PJ_STUN_OLD_STYLE_MI_FINGERPRINT
2737 // These are obsoleted in rfc3489bis-08
2738 if ((buf-start) & 0x3F) {
2739 pj_uint8_t zeroes[64];
2740 pj_bzero(zeroes, sizeof(zeroes));
2741 pj_hmac_sha1_update(&ctx, zeroes, 64-((buf-start) & 0x3F));
2742 }
2743 #endif /* PJ_STUN_OLD_STYLE_MI_FINGERPRINT */
2744 pj_hmac_sha1_final(&ctx, amsgint->hmac);
2745
2746 /* Put this attribute in the message */
2747 status = encode_msgint_attr(amsgint, buf, (unsigned)buf_size,
2748 &msg->hdr, &printed);
2749 if (status != PJ_SUCCESS)
2750 return status;
2751
2752 buf += printed;
2753 buf_size -= printed;
2754 }
2755
2756 /* Calculate FINGERPRINT if present */
2757 if (afingerprint != NULL) {
2758
2759 #if !PJ_STUN_OLD_STYLE_MI_FINGERPRINT
2760 /* Update message length */
2761 PUTVAL16H(start, 2,
2762 (pj_uint16_t)(GETVAL16H(start, 2)+8));
2763 #endif
2764
2765 afingerprint->value = pj_crc32_calc(start, buf-start);
2766 afingerprint->value ^= STUN_XOR_FINGERPRINT;
2767
2768 /* Put this attribute in the message */
2769 status = encode_uint_attr(afingerprint, buf, (unsigned)buf_size,
2770 &msg->hdr, &printed);
2771 if (status != PJ_SUCCESS)
2772 return status;
2773
2774 buf += printed;
2775 buf_size -= printed;
2776 }
2777
2778 /* Update message length. */
2779 msg->hdr.length = (pj_uint16_t) ((buf - start) - 20);
2780
2781 /* Return the length */
2782 if (p_msg_len)
2783 *p_msg_len = (buf - start);
2784
2785 return PJ_SUCCESS;
2786 }
2787
2788
2789 /*
2790 * Find STUN attribute in the STUN message, starting from the specified
2791 * index.
2792 */
pj_stun_msg_find_attr(const pj_stun_msg * msg,int attr_type,unsigned index)2793 PJ_DEF(pj_stun_attr_hdr*) pj_stun_msg_find_attr( const pj_stun_msg *msg,
2794 int attr_type,
2795 unsigned index)
2796 {
2797 PJ_ASSERT_RETURN(msg, NULL);
2798
2799 for (; index < msg->attr_count; ++index) {
2800 if (msg->attr[index]->type == attr_type)
2801 return (pj_stun_attr_hdr*) msg->attr[index];
2802 }
2803
2804 return NULL;
2805 }
2806
2807
2808 /*
2809 * Clone a STUN attribute.
2810 */
pj_stun_attr_clone(pj_pool_t * pool,const pj_stun_attr_hdr * attr)2811 PJ_DEF(pj_stun_attr_hdr*) pj_stun_attr_clone( pj_pool_t *pool,
2812 const pj_stun_attr_hdr *attr)
2813 {
2814 const struct attr_desc *adesc;
2815
2816 /* Get the attribute descriptor */
2817 adesc = find_attr_desc(attr->type);
2818 if (adesc) {
2819 return (pj_stun_attr_hdr*) (*adesc->clone_attr)(pool, attr);
2820 } else {
2821 /* Clone generic attribute */
2822 const pj_stun_binary_attr *bin_attr = (const pj_stun_binary_attr*)
2823 attr;
2824 PJ_ASSERT_RETURN(bin_attr->magic == PJ_STUN_MAGIC, NULL);
2825 if (bin_attr->magic == PJ_STUN_MAGIC) {
2826 return (pj_stun_attr_hdr*) clone_binary_attr(pool, attr);
2827 } else {
2828 return NULL;
2829 }
2830 }
2831 }
2832
2833
2834