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