yeayyy, stupid WLM2009 seems to generate wrong fingerprints from time to time (not...
[sipe-libnice.git] / stun / stunagent.c
blobfaad9251c3ed99e691141f6fdfbbab60978e2653
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2007 Nokia Corporation. All rights reserved.
5 * Contact: Rémi Denis-Courmont
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is the Nice GLib ICE library.
19 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
20 * Corporation. All Rights Reserved.
22 * Contributors:
23 * Rémi Denis-Courmont, Nokia
25 * Alternatively, the contents of this file may be used under the terms of the
26 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
27 * case the provisions of LGPL are applicable instead of those above. If you
28 * wish to allow use of your version of this file only under the terms of the
29 * LGPL and not to allow others to use your version of this file under the
30 * MPL, indicate your decision by deleting the provisions above and replace
31 * them with the notice and other provisions required by the LGPL. If you do
32 * not delete the provisions above, a recipient may use your version of this
33 * file under either the MPL or the LGPL.
36 #ifdef HAVE_CONFIG_H
37 # include <config.h>
38 #endif
40 #include "stunmessage.h"
41 #include "stunagent.h"
43 #include <string.h>
44 #include <stdlib.h>
47 static bool stun_agent_is_unknown (StunAgent *agent, uint16_t type);
48 static unsigned stun_agent_find_unknowns (StunAgent *agent,
49 const StunMessage * msg, uint16_t *list, unsigned max);
51 void stun_agent_init (StunAgent *agent, const uint16_t *known_attributes,
52 StunCompatibility compatibility, uint32_t usage_flags)
54 int i;
56 agent->known_attributes = (uint16_t *) known_attributes;
57 agent->compatibility = compatibility;
58 agent->usage_flags = usage_flags;
60 for (i = 0; i < STUN_AGENT_MAX_SAVED_IDS; i++) {
61 agent->sent_ids[i].valid = FALSE;
66 bool stun_agent_default_validater (StunAgent *agent,
67 StunMessage *message, uint8_t *username, uint16_t username_len,
68 uint8_t **password, size_t *password_len, void *user_data)
70 stun_validater_data* val = (stun_validater_data*) user_data;
71 int i;
73 for (i = 0; val && val[i].username ; i++) {
74 stun_debug ("Comparing username '");
75 stun_debug_bytes (username, username_len);
76 stun_debug ("' (%d) with '", username_len);
77 stun_debug_bytes (val[i].username, val[i].username_len);
78 stun_debug ("' (%d) : %d\n",
79 val[i].username_len, memcmp (username, val[i].username, username_len));
80 if (username_len == val[i].username_len &&
81 memcmp (username, val[i].username, username_len) == 0) {
82 *password = (uint8_t *) val[i].password;
83 *password_len = val[i].password_len;
84 stun_debug ("Found valid username, returning password : '%s'\n", *password);
85 return TRUE;
89 return FALSE;
93 StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
94 const uint8_t *buffer, size_t buffer_len,
95 StunMessageIntegrityValidate validater, void * validater_data)
97 stun_transid_t msg_id;
98 uint32_t fpr;
99 uint32_t crc32;
100 int len;
101 uint8_t *username = NULL;
102 uint16_t username_len;
103 uint8_t *key = NULL;
104 size_t key_len;
105 uint8_t *hash;
106 uint8_t sha[20];
107 uint16_t hlen;
108 int sent_id_idx = -1;
109 uint16_t unknown;
110 int error_code;
111 int ignore_credentials = 0;
112 uint8_t long_term_key[16];
113 bool long_term_key_valid = FALSE;
115 len = stun_message_validate_buffer_length (buffer, buffer_len);
116 if (len == STUN_MESSAGE_BUFFER_INVALID) {
117 return STUN_VALIDATION_NOT_STUN;
118 } else if (len == STUN_MESSAGE_BUFFER_INCOMPLETE) {
119 return STUN_VALIDATION_INCOMPLETE_STUN;
120 } else if (len != (int) buffer_len) {
121 return STUN_VALIDATION_NOT_STUN;
124 msg->buffer = (uint8_t *) buffer;
125 msg->buffer_len = buffer_len;
126 msg->agent = agent;
127 msg->key = NULL;
128 msg->key_len = 0;
129 msg->long_term_valid = FALSE;
131 /* TODO: reject it or not ? */
132 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
133 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
134 !stun_has_cookie (msg)) {
135 stun_debug ("STUN demux error: no cookie!\n");
136 return STUN_VALIDATION_BAD_REQUEST;
139 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
140 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
141 agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
142 /* Looks for FINGERPRINT */
143 if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) !=
144 STUN_MESSAGE_RETURN_SUCCESS) {
145 stun_debug ("STUN demux error: no FINGERPRINT attribute!\n");
146 return STUN_VALIDATION_BAD_REQUEST;
149 /* Checks FINGERPRINT */
150 crc32 = stun_fingerprint (msg->buffer, stun_message_length (msg));
151 fpr = ntohl (fpr);
152 if (fpr != crc32) {
153 stun_debug ("STUN demux error: bad fingerprint: 0x%08x,"
154 " expected: 0x%08x!\n", fpr, crc32);
155 if (agent->compatibility != STUN_COMPATIBILITY_WLM2009)
156 return STUN_VALIDATION_BAD_REQUEST;
159 stun_debug ("STUN demux: OK!\n");
162 if (stun_message_get_class (msg) == STUN_RESPONSE ||
163 stun_message_get_class (msg) == STUN_ERROR) {
164 stun_message_id (msg, msg_id);
165 for (sent_id_idx = 0; sent_id_idx < STUN_AGENT_MAX_SAVED_IDS; sent_id_idx++) {
166 if (agent->sent_ids[sent_id_idx].valid == TRUE &&
167 agent->sent_ids[sent_id_idx].method == stun_message_get_method (msg) &&
168 memcmp (msg_id, agent->sent_ids[sent_id_idx].id,
169 sizeof(stun_transid_t)) == 0) {
171 key = agent->sent_ids[sent_id_idx].key;
172 key_len = agent->sent_ids[sent_id_idx].key_len;
173 memcpy (long_term_key, agent->sent_ids[sent_id_idx].long_term_key,
174 sizeof(long_term_key));
175 long_term_key_valid = agent->sent_ids[sent_id_idx].long_term_valid;
176 break;
179 if (sent_id_idx == STUN_AGENT_MAX_SAVED_IDS) {
180 return STUN_VALIDATION_UNMATCHED_RESPONSE;
184 ignore_credentials =
185 (agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) ||
186 (stun_message_get_class (msg) == STUN_ERROR &&
187 stun_message_find_error (msg, &error_code) ==
188 STUN_MESSAGE_RETURN_SUCCESS &&
189 (error_code == 400 || error_code == 401)) ||
190 (stun_message_get_class (msg) == STUN_INDICATION &&
191 (agent->usage_flags & STUN_AGENT_USAGE_NO_INDICATION_AUTH));
193 if (key == NULL &&
194 ignore_credentials == 0 &&
195 (stun_message_get_class (msg) == STUN_REQUEST ||
196 stun_message_get_class (msg) == STUN_INDICATION) &&
197 (((agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS) &&
198 (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
199 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY))) ||
200 ((agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) &&
201 stun_message_get_class (msg) == STUN_REQUEST &&
202 (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
203 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) ||
204 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_NONCE) ||
205 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_REALM))) ||
206 ((agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) == 0 &&
207 stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) &&
208 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY)))) {
209 return STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST;
212 if (stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) &&
213 ((key == NULL && ignore_credentials == 0) ||
214 (agent->usage_flags & STUN_AGENT_USAGE_FORCE_VALIDATER))) {
215 username_len = 0;
216 username = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_USERNAME,
217 &username_len);
218 if (validater == NULL ||
219 validater (agent, msg, username, username_len,
220 &key, &key_len, validater_data) == FALSE) {
221 return STUN_VALIDATION_UNAUTHORIZED;
225 if (ignore_credentials == 0 && key != NULL && key_len > 0) {
226 hash = (uint8_t *) stun_message_find (msg,
227 STUN_ATTRIBUTE_MESSAGE_INTEGRITY, &hlen);
229 if (hash) {
230 /* We must give the size from start to the end of the attribute
231 because you might have a FINGERPRINT attribute after it... */
232 if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
233 uint8_t *realm = NULL;
234 uint8_t *username = NULL;
235 uint16_t realm_len;
236 uint16_t username_len;
237 uint8_t md5[16];
239 if (long_term_key_valid) {
240 memcpy (md5, long_term_key, sizeof (md5));
241 } else {
242 realm = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_REALM, &realm_len);
243 username = (uint8_t *) stun_message_find (msg,
244 STUN_ATTRIBUTE_USERNAME, &username_len);
245 if (username == NULL || realm == NULL) {
246 return STUN_VALIDATION_UNAUTHORIZED;
248 stun_hash_creds (realm, realm_len,
249 username, username_len,
250 key, key_len, md5);
253 memcpy (msg->long_term_key, md5, sizeof(md5));
254 msg->long_term_valid = TRUE;
256 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
257 stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
258 sha, md5, sizeof(md5), TRUE);
259 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
260 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
261 stun_message_length (msg) - 20, sha, md5, sizeof(md5), TRUE);
262 } else {
263 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
264 hash - msg->buffer, sha, md5, sizeof(md5), FALSE);
266 } else {
267 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
268 stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
269 sha, key, key_len, TRUE);
270 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
271 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
272 stun_message_length (msg) - 20, sha, key, key_len, TRUE);
273 } else {
274 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
275 hash - msg->buffer, sha, key, key_len, FALSE);
279 stun_debug (" Message HMAC-SHA1 fingerprint:");
280 stun_debug ("\nkey : ");
281 stun_debug_bytes (key, key_len);
282 stun_debug ("\n expected: ");
283 stun_debug_bytes (sha, sizeof (sha));
284 stun_debug ("\n received: ");
285 stun_debug_bytes (hash, sizeof (sha));
286 stun_debug ("\n");
288 if (memcmp (sha, hash, sizeof (sha))) {
289 stun_debug ("STUN auth error: SHA1 fingerprint mismatch!\n");
290 return STUN_VALIDATION_UNAUTHORIZED;
293 stun_debug ("STUN auth: OK!\n");
294 msg->key = key;
295 msg->key_len = key_len;
296 } else if (!(stun_message_get_class (msg) == STUN_ERROR &&
297 stun_message_find_error (msg, &error_code) ==
298 STUN_MESSAGE_RETURN_SUCCESS &&
299 (error_code == 400 || error_code == 401))) {
300 stun_debug ("STUN auth error: No message integrity attribute!\n");
301 return STUN_VALIDATION_UNAUTHORIZED;
306 if (sent_id_idx != -1 && sent_id_idx < STUN_AGENT_MAX_SAVED_IDS) {
307 agent->sent_ids[sent_id_idx].valid = FALSE;
310 if (stun_agent_find_unknowns (agent, msg, &unknown, 1) > 0) {
311 if (stun_message_get_class (msg) == STUN_REQUEST)
312 return STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE;
313 else
314 return STUN_VALIDATION_UNKNOWN_ATTRIBUTE;
316 return STUN_VALIDATION_SUCCESS;
321 bool stun_agent_init_request (StunAgent *agent, StunMessage *msg,
322 uint8_t *buffer, size_t buffer_len, stun_method_t m)
324 bool ret;
325 stun_transid_t id;
327 msg->buffer = buffer;
328 msg->buffer_len = buffer_len;
329 msg->agent = agent;
330 msg->key = NULL;
331 msg->key_len = 0;
332 msg->long_term_valid = FALSE;
334 stun_make_transid (id);
336 ret = stun_message_init (msg, STUN_REQUEST, m, id);
338 if (ret) {
339 if (agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
340 agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
341 uint32_t cookie = htonl (STUN_MAGIC_COOKIE);
342 memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie));
346 return ret;
350 bool stun_agent_init_indication (StunAgent *agent, StunMessage *msg,
351 uint8_t *buffer, size_t buffer_len, stun_method_t m)
353 bool ret;
354 stun_transid_t id;
356 msg->buffer = buffer;
357 msg->buffer_len = buffer_len;
358 msg->agent = agent;
359 msg->key = NULL;
360 msg->key_len = 0;
361 msg->long_term_valid = FALSE;
363 stun_make_transid (id);
364 ret = stun_message_init (msg, STUN_INDICATION, m, id);
366 if (ret) {
367 if (agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
368 agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
369 uint32_t cookie = htonl (STUN_MAGIC_COOKIE);
370 memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie));
374 return ret;
378 bool stun_agent_init_response (StunAgent *agent, StunMessage *msg,
379 uint8_t *buffer, size_t buffer_len, const StunMessage *request)
382 stun_transid_t id;
384 if (stun_message_get_class (request) != STUN_REQUEST) {
385 return FALSE;
388 msg->buffer = buffer;
389 msg->buffer_len = buffer_len;
390 msg->agent = agent;
391 msg->key = request->key;
392 msg->key_len = request->key_len;
393 memmove (msg->long_term_key, request->long_term_key,
394 sizeof(msg->long_term_key));
395 msg->long_term_valid = request->long_term_valid;
397 stun_message_id (request, id);
399 if (stun_message_init (msg, STUN_RESPONSE,
400 stun_message_get_method (request), id)) {
402 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
403 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
404 agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE) {
405 stun_message_append_software (msg);
407 return TRUE;
409 return FALSE;
413 bool stun_agent_init_error (StunAgent *agent, StunMessage *msg,
414 uint8_t *buffer, size_t buffer_len, const StunMessage *request,
415 stun_error_t err)
417 stun_transid_t id;
419 if (stun_message_get_class (request) != STUN_REQUEST) {
420 return FALSE;
423 msg->buffer = buffer;
424 msg->buffer_len = buffer_len;
425 msg->agent = agent;
426 msg->key = request->key;
427 msg->key_len = request->key_len;
428 memmove (msg->long_term_key, request->long_term_key,
429 sizeof(msg->long_term_key));
430 msg->long_term_valid = request->long_term_valid;
432 stun_message_id (request, id);
435 if (stun_message_init (msg, STUN_ERROR,
436 stun_message_get_method (request), id)) {
438 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
439 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
440 agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE) {
441 stun_message_append_software (msg);
443 if (stun_message_append_error (msg, err) == STUN_MESSAGE_RETURN_SUCCESS) {
444 return TRUE;
447 return FALSE;
451 size_t stun_agent_build_unknown_attributes_error (StunAgent *agent,
452 StunMessage *msg, uint8_t *buffer, size_t buffer_len,
453 const StunMessage *request)
456 unsigned counter;
457 uint16_t ids[STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES];
459 counter = stun_agent_find_unknowns (agent, request,
460 ids, STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES);
462 if (stun_agent_init_error (agent, msg, buffer, buffer_len,
463 request, STUN_ERROR_UNKNOWN_ATTRIBUTE) == FALSE) {
464 return 0;
467 /* NOTE: Old RFC3489 compatibility:
468 * When counter is odd, duplicate one value for 32-bits padding. */
469 if (!stun_has_cookie (request) && (counter & 1))
470 ids[counter++] = ids[0];
472 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES,
473 ids, counter * 2) == STUN_MESSAGE_RETURN_SUCCESS) {
474 return stun_agent_finish_message (agent, msg, request->key, request->key_len);
477 return 0;
481 size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
482 const uint8_t *key, size_t key_len)
484 uint8_t *ptr;
485 uint32_t fpr;
486 int i;
487 stun_transid_t id;
488 uint8_t md5[16];
490 if (msg->key != NULL) {
491 key = msg->key;
492 key_len = msg->key_len;
495 if (key != NULL) {
496 bool skip = FALSE;
498 if (msg->long_term_valid) {
499 memcpy (md5, msg->long_term_key, sizeof(msg->long_term_key));
500 } else if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
501 uint8_t *realm = NULL;
502 uint8_t *username = NULL;
503 uint16_t realm_len;
504 uint16_t username_len;
506 realm = (uint8_t *) stun_message_find (msg,
507 STUN_ATTRIBUTE_REALM, &realm_len);
508 username = (uint8_t *) stun_message_find (msg,
509 STUN_ATTRIBUTE_USERNAME, &username_len);
510 if (username == NULL || realm == NULL) {
511 skip = TRUE;
512 } else {
513 stun_hash_creds (realm, realm_len,
514 username, username_len,
515 key, key_len, md5);
517 memcpy (msg->long_term_key, md5, sizeof(msg->long_term_key));
518 msg->long_term_valid = TRUE;
521 /* If no realm/username and long term credentials,
522 then don't send the message integrity */
523 if (skip == FALSE) {
524 ptr = stun_message_append (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, 20);
525 if (ptr == NULL) {
526 return 0;
528 if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
529 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
530 stun_sha1 (msg->buffer, stun_message_length (msg),
531 stun_message_length (msg) - 20, ptr, md5, sizeof(md5), TRUE);
532 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
533 size_t minus = 20;
534 if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
535 minus -= 8;
537 stun_sha1 (msg->buffer, stun_message_length (msg),
538 stun_message_length (msg) - minus, ptr, md5, sizeof(md5), TRUE);
539 } else {
540 stun_sha1 (msg->buffer, stun_message_length (msg),
541 stun_message_length (msg) - 20, ptr, md5, sizeof(md5), FALSE);
543 } else {
544 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
545 stun_sha1 (msg->buffer, stun_message_length (msg),
546 stun_message_length (msg) - 20, ptr, key, key_len, TRUE);
547 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
548 size_t minus = 20;
549 if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
550 minus -= 8;
552 stun_sha1 (msg->buffer, stun_message_length (msg),
553 stun_message_length (msg) - minus, ptr, key, key_len, TRUE);
554 } else {
555 stun_sha1 (msg->buffer, stun_message_length (msg),
556 stun_message_length (msg) - 20, ptr, key, key_len, FALSE);
560 stun_debug (" Message HMAC-SHA1 message integrity:"
561 "\n key : ");
562 stun_debug_bytes (key, key_len);
563 stun_debug ("\n sent : ");
564 stun_debug_bytes (ptr, 20);
565 stun_debug ("\n");
569 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
570 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
571 agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
572 ptr = stun_message_append (msg, STUN_ATTRIBUTE_FINGERPRINT, 4);
573 if (ptr == NULL) {
574 return 0;
578 fpr = stun_fingerprint (msg->buffer, stun_message_length (msg));
579 memcpy (ptr, &fpr, sizeof (fpr));
581 stun_debug (" Message HMAC-SHA1 fingerprint: ");
582 stun_debug_bytes (ptr, 4);
583 stun_debug ("\n");
587 if (stun_message_get_class (msg) == STUN_REQUEST) {
588 for (i = 0; i < STUN_AGENT_MAX_SAVED_IDS; i++) {
589 if (agent->sent_ids[i].valid == FALSE) {
590 stun_message_id (msg, id);
591 memcpy (agent->sent_ids[i].id, id, sizeof(stun_transid_t));
592 agent->sent_ids[i].method = stun_message_get_method (msg);
593 agent->sent_ids[i].key = (uint8_t *) key;
594 agent->sent_ids[i].key_len = key_len;
595 memcpy (agent->sent_ids[i].long_term_key, msg->long_term_key,
596 sizeof(msg->long_term_key));
597 agent->sent_ids[i].long_term_valid = msg->long_term_valid;
598 agent->sent_ids[i].valid = TRUE;
599 break;
604 msg->key = (uint8_t *) key;
605 msg->key_len = key_len;
606 return stun_message_length (msg);
610 static bool stun_agent_is_unknown (StunAgent *agent, uint16_t type)
613 uint16_t *known_attr = agent->known_attributes;
615 while(*known_attr != 0) {
616 if (*known_attr == type) {
617 return FALSE;
619 known_attr++;
622 return TRUE;
627 static unsigned
628 stun_agent_find_unknowns (StunAgent *agent, const StunMessage * msg,
629 uint16_t *list, unsigned max)
631 unsigned count = 0;
632 uint16_t len = stun_message_length (msg);
633 size_t offset = 0;
635 offset = STUN_MESSAGE_ATTRIBUTES_POS;
637 while ((offset < len) && (count < max))
639 size_t alen = stun_getw (msg->buffer + offset + STUN_ATTRIBUTE_TYPE_LEN);
640 uint16_t atype = stun_getw (msg->buffer + offset);
642 offset += STUN_ATTRIBUTE_VALUE_POS + stun_align (alen);
644 if (!stun_optional (atype) && stun_agent_is_unknown (agent, atype))
646 stun_debug ("STUN unknown: attribute 0x%04x(%u bytes)\n",
647 (unsigned)atype, (unsigned)alen);
648 list[count++] = htons (atype);
652 stun_debug ("STUN unknown: %u mandatory attribute(s)!\n", count);
653 return count;