2 * This file is part of the Nice GLib ICE library.
4 * (C) 2008-2009 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2008-2009 Nokia Corporation. All rights reserved.
8 * The contents of this file are subject to the Mozilla Public License Version
9 * 1.1 (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
13 * Software distributed under the License is distributed on an "AS IS" basis,
14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15 * for the specific language governing rights and limitations under the
18 * The Original Code is the Nice GLib ICE library.
20 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
21 * Corporation. All Rights Reserved.
24 * Youness Alaoui, Collabora Ltd.
26 * Alternatively, the contents of this file may be used under the terms of the
27 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
28 * case the provisions of LGPL are applicable instead of those above. If you
29 * wish to allow use of your version of this file only under the terms of the
30 * LGPL and not to allow others to use your version of this file under the
31 * MPL, indicate your decision by deleting the provisions above and replace
32 * them with the notice and other provisions required by the LGPL. If you do
33 * not delete the provisions above, a recipient may use your version of this
34 * file under either the MPL or the LGPL.
41 #include "stunmessage.h"
42 #include "stunagent.h"
51 static bool stun_agent_is_unknown (StunAgent
*agent
, uint16_t type
);
52 static unsigned stun_agent_find_unknowns (StunAgent
*agent
,
53 const StunMessage
* msg
, uint16_t *list
, unsigned max
);
55 void stun_agent_init (StunAgent
*agent
, const uint16_t *known_attributes
,
56 StunCompatibility compatibility
, StunAgentUsageFlags usage_flags
)
60 agent
->known_attributes
= (uint16_t *) known_attributes
;
61 agent
->compatibility
= compatibility
;
62 agent
->usage_flags
= usage_flags
;
63 agent
->software_attribute
= NULL
;
65 for (i
= 0; i
< STUN_AGENT_MAX_SAVED_IDS
; i
++) {
66 agent
->sent_ids
[i
].valid
= FALSE
;
71 bool stun_agent_default_validater (StunAgent
*agent
,
72 StunMessage
*message
, uint8_t *username
, uint16_t username_len
,
73 uint8_t **password
, size_t *password_len
, void *user_data
)
75 StunDefaultValidaterData
* val
= (StunDefaultValidaterData
*) user_data
;
78 for (i
= 0; val
&& val
[i
].username
; i
++) {
79 stun_debug ("Comparing username '");
80 stun_debug_bytes (username
, username_len
);
81 stun_debug ("' (%d) with '", username_len
);
82 stun_debug_bytes (val
[i
].username
, val
[i
].username_len
);
83 stun_debug ("' (%d) : %d\n",
84 val
[i
].username_len
, memcmp (username
, val
[i
].username
, username_len
));
85 if (username_len
== val
[i
].username_len
&&
86 memcmp (username
, val
[i
].username
, username_len
) == 0) {
87 *password
= (uint8_t *) val
[i
].password
;
88 *password_len
= val
[i
].password_len
;
89 stun_debug ("Found valid username, returning password : '%s'\n", *password
);
98 StunValidationStatus
stun_agent_validate (StunAgent
*agent
, StunMessage
*msg
,
99 const uint8_t *buffer
, size_t buffer_len
,
100 StunMessageIntegrityValidate validater
, void * validater_data
)
102 StunTransactionId msg_id
;
106 uint8_t *username
= NULL
;
107 uint16_t username_len
;
113 int sent_id_idx
= -1;
116 int ignore_credentials
= 0;
117 uint8_t long_term_key
[16];
118 bool long_term_key_valid
= FALSE
;
120 len
= stun_message_validate_buffer_length (buffer
, buffer_len
,
121 !(agent
->usage_flags
& STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES
));
122 if (len
== STUN_MESSAGE_BUFFER_INVALID
) {
123 return STUN_VALIDATION_NOT_STUN
;
124 } else if (len
== STUN_MESSAGE_BUFFER_INCOMPLETE
) {
125 return STUN_VALIDATION_INCOMPLETE_STUN
;
126 } else if (len
!= (int) buffer_len
) {
127 return STUN_VALIDATION_NOT_STUN
;
130 msg
->buffer
= (uint8_t *) buffer
;
131 msg
->buffer_len
= buffer_len
;
135 msg
->long_term_valid
= FALSE
;
137 /* TODO: reject it or not ? */
138 if ((agent
->compatibility
== STUN_COMPATIBILITY_RFC5389
||
139 agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) &&
140 !stun_message_has_cookie (msg
)) {
141 stun_debug ("STUN demux error: no cookie!\n");
142 return STUN_VALIDATION_BAD_REQUEST
;
145 if ((agent
->compatibility
== STUN_COMPATIBILITY_RFC5389
||
146 agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) &&
147 agent
->usage_flags
& STUN_AGENT_USAGE_USE_FINGERPRINT
) {
148 /* Looks for FINGERPRINT */
149 if (stun_message_find32 (msg
, STUN_ATTRIBUTE_FINGERPRINT
, &fpr
) !=
150 STUN_MESSAGE_RETURN_SUCCESS
) {
151 stun_debug ("STUN demux error: no FINGERPRINT attribute!\n");
152 return STUN_VALIDATION_BAD_REQUEST
;
154 /* Checks FINGERPRINT */
155 crc32
= stun_fingerprint (msg
->buffer
, stun_message_length (msg
),
156 agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
);
159 stun_debug ("STUN demux error: bad fingerprint: 0x%08x,"
160 " expected: 0x%08x!\n", fpr
, crc32
);
161 return STUN_VALIDATION_BAD_REQUEST
;
164 stun_debug ("STUN demux: OK!\n");
167 if (stun_message_get_class (msg
) == STUN_RESPONSE
||
168 stun_message_get_class (msg
) == STUN_ERROR
) {
169 stun_message_id (msg
, msg_id
);
170 for (sent_id_idx
= 0; sent_id_idx
< STUN_AGENT_MAX_SAVED_IDS
; sent_id_idx
++) {
171 if (agent
->sent_ids
[sent_id_idx
].valid
== TRUE
&&
172 agent
->sent_ids
[sent_id_idx
].method
== stun_message_get_method (msg
) &&
173 memcmp (msg_id
, agent
->sent_ids
[sent_id_idx
].id
,
174 sizeof(StunTransactionId
)) == 0) {
176 key
= agent
->sent_ids
[sent_id_idx
].key
;
177 key_len
= agent
->sent_ids
[sent_id_idx
].key_len
;
178 memcpy (long_term_key
, agent
->sent_ids
[sent_id_idx
].long_term_key
,
179 sizeof(long_term_key
));
180 long_term_key_valid
= agent
->sent_ids
[sent_id_idx
].long_term_valid
;
184 if (sent_id_idx
== STUN_AGENT_MAX_SAVED_IDS
) {
185 return STUN_VALIDATION_UNMATCHED_RESPONSE
;
190 (agent
->usage_flags
& STUN_AGENT_USAGE_IGNORE_CREDENTIALS
) ||
191 (stun_message_get_class (msg
) == STUN_ERROR
&&
192 stun_message_find_error (msg
, &error_code
) ==
193 STUN_MESSAGE_RETURN_SUCCESS
&&
194 (error_code
== 400 || error_code
== 401)) ||
195 (stun_message_get_class (msg
) == STUN_INDICATION
&&
196 (agent
->usage_flags
& STUN_AGENT_USAGE_NO_INDICATION_AUTH
));
199 ignore_credentials
== 0 &&
200 (stun_message_get_class (msg
) == STUN_REQUEST
||
201 stun_message_get_class (msg
) == STUN_INDICATION
) &&
202 (((agent
->usage_flags
& STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
) &&
203 (!stun_message_has_attribute (msg
, STUN_ATTRIBUTE_USERNAME
) ||
204 !stun_message_has_attribute (msg
, STUN_ATTRIBUTE_MESSAGE_INTEGRITY
))) ||
205 ((agent
->usage_flags
& STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS
) &&
206 stun_message_get_class (msg
) == STUN_REQUEST
&&
207 (!stun_message_has_attribute (msg
, STUN_ATTRIBUTE_USERNAME
) ||
208 !stun_message_has_attribute (msg
, STUN_ATTRIBUTE_MESSAGE_INTEGRITY
) ||
209 !stun_message_has_attribute (msg
, STUN_ATTRIBUTE_NONCE
) ||
210 !stun_message_has_attribute (msg
, STUN_ATTRIBUTE_REALM
))) ||
211 ((agent
->usage_flags
& STUN_AGENT_USAGE_IGNORE_CREDENTIALS
) == 0 &&
212 stun_message_has_attribute (msg
, STUN_ATTRIBUTE_USERNAME
) &&
213 !stun_message_has_attribute (msg
, STUN_ATTRIBUTE_MESSAGE_INTEGRITY
)))) {
214 return STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST
;
217 if (stun_message_has_attribute (msg
, STUN_ATTRIBUTE_MESSAGE_INTEGRITY
) &&
218 ((key
== NULL
&& ignore_credentials
== 0) ||
219 (agent
->usage_flags
& STUN_AGENT_USAGE_FORCE_VALIDATER
))) {
221 username
= (uint8_t *) stun_message_find (msg
, STUN_ATTRIBUTE_USERNAME
,
223 if (validater
== NULL
||
224 validater (agent
, msg
, username
, username_len
,
225 &key
, &key_len
, validater_data
) == FALSE
) {
226 return STUN_VALIDATION_UNAUTHORIZED
;
230 if (ignore_credentials
== 0 && key
!= NULL
&& key_len
> 0) {
231 hash
= (uint8_t *) stun_message_find (msg
,
232 STUN_ATTRIBUTE_MESSAGE_INTEGRITY
, &hlen
);
235 /* We must give the size from start to the end of the attribute
236 because you might have a FINGERPRINT attribute after it... */
237 if (agent
->usage_flags
& STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS
) {
238 uint8_t *realm
= NULL
;
239 uint8_t *username
= NULL
;
241 uint16_t username_len
;
244 if (long_term_key_valid
) {
245 memcpy (md5
, long_term_key
, sizeof (md5
));
247 realm
= (uint8_t *) stun_message_find (msg
, STUN_ATTRIBUTE_REALM
, &realm_len
);
248 username
= (uint8_t *) stun_message_find (msg
,
249 STUN_ATTRIBUTE_USERNAME
, &username_len
);
250 if (username
== NULL
|| realm
== NULL
) {
251 return STUN_VALIDATION_UNAUTHORIZED
;
253 stun_hash_creds (realm
, realm_len
,
254 username
, username_len
,
258 memcpy (msg
->long_term_key
, md5
, sizeof(md5
));
259 msg
->long_term_valid
= TRUE
;
261 if (agent
->compatibility
== STUN_COMPATIBILITY_RFC3489
||
262 agent
->compatibility
== STUN_COMPATIBILITY_OC2007
) {
263 stun_sha1 (msg
->buffer
, hash
+ 20 - msg
->buffer
, hash
- msg
->buffer
,
264 sha
, md5
, sizeof(md5
), TRUE
);
265 } else if (agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) {
266 stun_sha1 (msg
->buffer
, hash
+ 20 - msg
->buffer
,
267 stun_message_length (msg
) - 20, sha
, md5
, sizeof(md5
), TRUE
);
269 stun_sha1 (msg
->buffer
, hash
+ 20 - msg
->buffer
,
270 hash
- msg
->buffer
, sha
, md5
, sizeof(md5
), FALSE
);
273 if (agent
->compatibility
== STUN_COMPATIBILITY_RFC3489
||
274 agent
->compatibility
== STUN_COMPATIBILITY_OC2007
) {
275 stun_sha1 (msg
->buffer
, hash
+ 20 - msg
->buffer
, hash
- msg
->buffer
,
276 sha
, key
, key_len
, TRUE
);
277 } else if (agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) {
278 stun_sha1 (msg
->buffer
, hash
+ 20 - msg
->buffer
,
279 stun_message_length (msg
) - 20, sha
, key
, key_len
, TRUE
);
281 stun_sha1 (msg
->buffer
, hash
+ 20 - msg
->buffer
,
282 hash
- msg
->buffer
, sha
, key
, key_len
, FALSE
);
286 stun_debug (" Message HMAC-SHA1 fingerprint:");
287 stun_debug ("\nkey : ");
288 stun_debug_bytes (key
, key_len
);
289 stun_debug ("\n expected: ");
290 stun_debug_bytes (sha
, sizeof (sha
));
291 stun_debug ("\n received: ");
292 stun_debug_bytes (hash
, sizeof (sha
));
295 if (memcmp (sha
, hash
, sizeof (sha
))) {
296 stun_debug ("STUN auth error: SHA1 fingerprint mismatch!\n");
297 return STUN_VALIDATION_UNAUTHORIZED
;
300 stun_debug ("STUN auth: OK!\n");
302 msg
->key_len
= key_len
;
303 } else if (!(stun_message_get_class (msg
) == STUN_ERROR
&&
304 stun_message_find_error (msg
, &error_code
) ==
305 STUN_MESSAGE_RETURN_SUCCESS
&&
306 (error_code
== 400 || error_code
== 401))) {
307 stun_debug ("STUN auth error: No message integrity attribute!\n");
308 return STUN_VALIDATION_UNAUTHORIZED
;
313 if (sent_id_idx
!= -1 && sent_id_idx
< STUN_AGENT_MAX_SAVED_IDS
) {
314 agent
->sent_ids
[sent_id_idx
].valid
= FALSE
;
317 if (stun_agent_find_unknowns (agent
, msg
, &unknown
, 1) > 0) {
318 if (stun_message_get_class (msg
) == STUN_REQUEST
)
319 return STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE
;
321 return STUN_VALIDATION_UNKNOWN_ATTRIBUTE
;
323 return STUN_VALIDATION_SUCCESS
;
327 bool stun_agent_forget_transaction (StunAgent
*agent
, StunTransactionId id
)
331 for (i
= 0; i
< STUN_AGENT_MAX_SAVED_IDS
; i
++) {
332 if (agent
->sent_ids
[i
].valid
== TRUE
&&
333 memcmp (id
, agent
->sent_ids
[i
].id
,
334 sizeof(StunTransactionId
)) == 0) {
335 agent
->sent_ids
[i
].valid
= FALSE
;
343 bool stun_agent_init_request (StunAgent
*agent
, StunMessage
*msg
,
344 uint8_t *buffer
, size_t buffer_len
, StunMethod m
)
347 StunTransactionId id
;
349 msg
->buffer
= buffer
;
350 msg
->buffer_len
= buffer_len
;
354 msg
->long_term_valid
= FALSE
;
356 stun_make_transid (id
);
358 ret
= stun_message_init (msg
, STUN_REQUEST
, m
, id
);
361 if (agent
->compatibility
== STUN_COMPATIBILITY_RFC5389
||
362 agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) {
363 uint32_t cookie
= htonl (STUN_MAGIC_COOKIE
);
364 memcpy (msg
->buffer
+ STUN_MESSAGE_TRANS_ID_POS
, &cookie
, sizeof (cookie
));
366 if ((agent
->compatibility
== STUN_COMPATIBILITY_RFC5389
||
367 agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) &&
368 (agent
->software_attribute
!= NULL
||
369 agent
->usage_flags
& STUN_AGENT_USAGE_ADD_SOFTWARE
)) {
370 stun_message_append_software (msg
, agent
->software_attribute
);
378 bool stun_agent_init_indication (StunAgent
*agent
, StunMessage
*msg
,
379 uint8_t *buffer
, size_t buffer_len
, StunMethod m
)
382 StunTransactionId id
;
384 msg
->buffer
= buffer
;
385 msg
->buffer_len
= buffer_len
;
389 msg
->long_term_valid
= FALSE
;
391 stun_make_transid (id
);
392 ret
= stun_message_init (msg
, STUN_INDICATION
, m
, id
);
395 if (agent
->compatibility
== STUN_COMPATIBILITY_RFC5389
||
396 agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) {
397 uint32_t cookie
= htonl (STUN_MAGIC_COOKIE
);
398 memcpy (msg
->buffer
+ STUN_MESSAGE_TRANS_ID_POS
, &cookie
, sizeof (cookie
));
406 bool stun_agent_init_response (StunAgent
*agent
, StunMessage
*msg
,
407 uint8_t *buffer
, size_t buffer_len
, const StunMessage
*request
)
410 StunTransactionId id
;
412 if (stun_message_get_class (request
) != STUN_REQUEST
) {
416 msg
->buffer
= buffer
;
417 msg
->buffer_len
= buffer_len
;
419 msg
->key
= request
->key
;
420 msg
->key_len
= request
->key_len
;
421 memmove (msg
->long_term_key
, request
->long_term_key
,
422 sizeof(msg
->long_term_key
));
423 msg
->long_term_valid
= request
->long_term_valid
;
425 stun_message_id (request
, id
);
427 if (stun_message_init (msg
, STUN_RESPONSE
,
428 stun_message_get_method (request
), id
)) {
430 if ((agent
->compatibility
== STUN_COMPATIBILITY_RFC5389
||
431 agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) &&
432 (agent
->software_attribute
!= NULL
||
433 agent
->usage_flags
& STUN_AGENT_USAGE_ADD_SOFTWARE
)) {
434 stun_message_append_software (msg
, agent
->software_attribute
);
442 bool stun_agent_init_error (StunAgent
*agent
, StunMessage
*msg
,
443 uint8_t *buffer
, size_t buffer_len
, const StunMessage
*request
,
446 StunTransactionId id
;
448 if (stun_message_get_class (request
) != STUN_REQUEST
) {
452 msg
->buffer
= buffer
;
453 msg
->buffer_len
= buffer_len
;
455 msg
->key
= request
->key
;
456 msg
->key_len
= request
->key_len
;
457 memmove (msg
->long_term_key
, request
->long_term_key
,
458 sizeof(msg
->long_term_key
));
459 msg
->long_term_valid
= request
->long_term_valid
;
461 stun_message_id (request
, id
);
464 if (stun_message_init (msg
, STUN_ERROR
,
465 stun_message_get_method (request
), id
)) {
467 if ((agent
->compatibility
== STUN_COMPATIBILITY_RFC5389
||
468 agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) &&
469 (agent
->software_attribute
!= NULL
||
470 agent
->usage_flags
& STUN_AGENT_USAGE_ADD_SOFTWARE
)) {
471 stun_message_append_software (msg
, agent
->software_attribute
);
473 if (stun_message_append_error (msg
, err
) == STUN_MESSAGE_RETURN_SUCCESS
) {
481 size_t stun_agent_build_unknown_attributes_error (StunAgent
*agent
,
482 StunMessage
*msg
, uint8_t *buffer
, size_t buffer_len
,
483 const StunMessage
*request
)
487 uint16_t ids
[STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES
];
489 counter
= stun_agent_find_unknowns (agent
, request
,
490 ids
, STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES
);
492 if (stun_agent_init_error (agent
, msg
, buffer
, buffer_len
,
493 request
, STUN_ERROR_UNKNOWN_ATTRIBUTE
) == FALSE
) {
497 /* NOTE: Old RFC3489 compatibility:
498 * When counter is odd, duplicate one value for 32-bits padding. */
499 if (!stun_message_has_cookie (request
) && (counter
& 1))
500 ids
[counter
++] = ids
[0];
502 if (stun_message_append_bytes (msg
, STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES
,
503 ids
, counter
* 2) == STUN_MESSAGE_RETURN_SUCCESS
) {
504 return stun_agent_finish_message (agent
, msg
, request
->key
, request
->key_len
);
511 size_t stun_agent_finish_message (StunAgent
*agent
, StunMessage
*msg
,
512 const uint8_t *key
, size_t key_len
)
516 int saved_id_idx
= 0;
519 if (stun_message_get_class (msg
) == STUN_REQUEST
) {
520 for (saved_id_idx
= 0; saved_id_idx
< STUN_AGENT_MAX_SAVED_IDS
; saved_id_idx
++) {
521 if (agent
->sent_ids
[saved_id_idx
].valid
== FALSE
) {
526 if (saved_id_idx
== STUN_AGENT_MAX_SAVED_IDS
) {
527 stun_debug ("Saved ids full");
531 if (msg
->key
!= NULL
) {
533 key_len
= msg
->key_len
;
539 if (msg
->long_term_valid
) {
540 memcpy (md5
, msg
->long_term_key
, sizeof(msg
->long_term_key
));
541 } else if (agent
->usage_flags
& STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS
) {
542 uint8_t *realm
= NULL
;
543 uint8_t *username
= NULL
;
545 uint16_t username_len
;
547 realm
= (uint8_t *) stun_message_find (msg
,
548 STUN_ATTRIBUTE_REALM
, &realm_len
);
549 username
= (uint8_t *) stun_message_find (msg
,
550 STUN_ATTRIBUTE_USERNAME
, &username_len
);
551 if (username
== NULL
|| realm
== NULL
) {
554 stun_hash_creds (realm
, realm_len
,
555 username
, username_len
,
558 memcpy (msg
->long_term_key
, md5
, sizeof(msg
->long_term_key
));
559 msg
->long_term_valid
= TRUE
;
562 /* If no realm/username and long term credentials,
563 then don't send the message integrity */
565 ptr
= stun_message_append (msg
, STUN_ATTRIBUTE_MESSAGE_INTEGRITY
, 20);
569 if (agent
->usage_flags
& STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS
) {
570 if (agent
->compatibility
== STUN_COMPATIBILITY_RFC3489
||
571 agent
->compatibility
== STUN_COMPATIBILITY_OC2007
) {
572 stun_sha1 (msg
->buffer
, stun_message_length (msg
),
573 stun_message_length (msg
) - 20, ptr
, md5
, sizeof(md5
), TRUE
);
574 } else if (agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) {
576 if (agent
->usage_flags
& STUN_AGENT_USAGE_USE_FINGERPRINT
)
579 stun_sha1 (msg
->buffer
, stun_message_length (msg
),
580 stun_message_length (msg
) - minus
, ptr
, md5
, sizeof(md5
), TRUE
);
582 stun_sha1 (msg
->buffer
, stun_message_length (msg
),
583 stun_message_length (msg
) - 20, ptr
, md5
, sizeof(md5
), FALSE
);
586 if (agent
->compatibility
== STUN_COMPATIBILITY_RFC3489
||
587 agent
->compatibility
== STUN_COMPATIBILITY_OC2007
) {
588 stun_sha1 (msg
->buffer
, stun_message_length (msg
),
589 stun_message_length (msg
) - 20, ptr
, key
, key_len
, TRUE
);
590 } else if (agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) {
592 if (agent
->usage_flags
& STUN_AGENT_USAGE_USE_FINGERPRINT
)
595 stun_sha1 (msg
->buffer
, stun_message_length (msg
),
596 stun_message_length (msg
) - minus
, ptr
, key
, key_len
, TRUE
);
598 stun_sha1 (msg
->buffer
, stun_message_length (msg
),
599 stun_message_length (msg
) - 20, ptr
, key
, key_len
, FALSE
);
603 stun_debug (" Message HMAC-SHA1 message integrity:"
605 stun_debug_bytes (key
, key_len
);
606 stun_debug ("\n sent : ");
607 stun_debug_bytes (ptr
, 20);
612 if ((agent
->compatibility
== STUN_COMPATIBILITY_RFC5389
||
613 agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
) &&
614 agent
->usage_flags
& STUN_AGENT_USAGE_USE_FINGERPRINT
) {
615 ptr
= stun_message_append (msg
, STUN_ATTRIBUTE_FINGERPRINT
, 4);
620 fpr
= stun_fingerprint (msg
->buffer
, stun_message_length (msg
),
621 agent
->compatibility
== STUN_COMPATIBILITY_WLM2009
);
622 memcpy (ptr
, &fpr
, sizeof (fpr
));
624 stun_debug (" Message HMAC-SHA1 fingerprint: ");
625 stun_debug_bytes (ptr
, 4);
630 if (stun_message_get_class (msg
) == STUN_REQUEST
) {
631 stun_message_id (msg
, agent
->sent_ids
[saved_id_idx
].id
);
632 agent
->sent_ids
[saved_id_idx
].method
= stun_message_get_method (msg
);
633 agent
->sent_ids
[saved_id_idx
].key
= (uint8_t *) key
;
634 agent
->sent_ids
[saved_id_idx
].key_len
= key_len
;
635 memcpy (agent
->sent_ids
[saved_id_idx
].long_term_key
, msg
->long_term_key
,
636 sizeof(msg
->long_term_key
));
637 agent
->sent_ids
[saved_id_idx
].long_term_valid
= msg
->long_term_valid
;
638 agent
->sent_ids
[saved_id_idx
].valid
= TRUE
;
641 msg
->key
= (uint8_t *) key
;
642 msg
->key_len
= key_len
;
643 return stun_message_length (msg
);
647 static bool stun_agent_is_unknown (StunAgent
*agent
, uint16_t type
)
650 uint16_t *known_attr
= agent
->known_attributes
;
652 while(*known_attr
!= 0) {
653 if (*known_attr
== type
) {
665 stun_agent_find_unknowns (StunAgent
*agent
, const StunMessage
* msg
,
666 uint16_t *list
, unsigned max
)
669 uint16_t len
= stun_message_length (msg
);
672 offset
= STUN_MESSAGE_ATTRIBUTES_POS
;
674 while ((offset
< len
) && (count
< max
))
676 size_t alen
= stun_getw (msg
->buffer
+ offset
+ STUN_ATTRIBUTE_TYPE_LEN
);
677 uint16_t atype
= stun_getw (msg
->buffer
+ offset
);
679 if (!stun_optional (atype
) && stun_agent_is_unknown (agent
, atype
))
681 stun_debug ("STUN unknown: attribute 0x%04x(%u bytes)\n",
682 (unsigned)atype
, (unsigned)alen
);
683 list
[count
++] = htons (atype
);
686 if (!(agent
->usage_flags
& STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES
))
687 alen
= stun_align (alen
);
689 offset
+= STUN_ATTRIBUTE_VALUE_POS
+ alen
;
692 stun_debug ("STUN unknown: %u mandatory attribute(s)!\n", count
);
696 void stun_agent_set_software (StunAgent
*agent
, const char *software
)
698 agent
->software_attribute
= software
;