StunUsageTurnReturn stun_usage_turn_refresh_process (StunMessage *msg, uint32_t *lifetime, StunUsageTurnCompatibility compatibility) { int code = -1; StunUsageTurnReturn ret = STUN_USAGE_TURN_RETURN_RELAY_SUCCESS; if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9 || compatibility == STUN_USAGE_TURN_COMPATIBILITY_RFC5766) { if (stun_message_get_method (msg) != STUN_REFRESH) return STUN_USAGE_TURN_RETURN_INVALID; } else { if (stun_message_get_method (msg) != STUN_ALLOCATE) return STUN_USAGE_TURN_RETURN_INVALID; } switch (stun_message_get_class (msg)) { case STUN_REQUEST: case STUN_INDICATION: return STUN_USAGE_TURN_RETURN_INVALID; case STUN_RESPONSE: break; case STUN_ERROR: if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) { /* missing ERROR-CODE: ignore message */ return STUN_USAGE_TURN_RETURN_INVALID; } return STUN_USAGE_TURN_RETURN_ERROR; default: /* Fall through. */ break; } stun_message_find32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime); stun_debug ("TURN Refresh successful!\n"); return ret; }
int main (void) { union { struct sockaddr sa; struct sockaddr_storage storage; struct sockaddr_in ip4; } addr; uint8_t req_buf[STUN_MAX_MESSAGE_SIZE]; uint8_t resp_buf[STUN_MAX_MESSAGE_SIZE]; const const uint64_t tie = 0x8000000000000000LL; StunMessageReturn val; StunUsageIceReturn val2; size_t len; size_t rlen; static char username[] = "L:R"; static uint8_t ufrag[] = "L", pass[] = "secret"; size_t ufrag_len = strlen ((char*) ufrag); size_t pass_len = strlen ((char*) pass); int code; bool control = false; StunAgent agent; StunMessage req; StunMessage resp; StunDefaultValidaterData validater_data[] = { {ufrag, ufrag_len, pass, pass_len}, {(uint8_t *) username, strlen (username), pass, pass_len}, {NULL, 0, NULL, 0}}; StunValidationStatus valid; stun_agent_init (&agent, STUN_ALL_KNOWN_ATTRIBUTES, STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT | STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS); memset (&addr, 0, sizeof (addr)); addr.ip4.sin_family = AF_INET; #ifdef HAVE_SA_LEN addr.ip4.sin_len = sizeof (addr); #endif addr.ip4.sin_port = htons (12345); addr.ip4.sin_addr.s_addr = htonl (0x7f000001); /* Incorrect message class */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); assert (stun_agent_init_response (&agent, &req, req_buf, sizeof (req_buf), &req)); rlen = stun_agent_finish_message (&agent, &req, NULL, 0); assert (rlen > 0); len = sizeof (resp_buf); val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_INVALID_REQUEST); assert (len == 0); /* Incorrect message method */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), 0x666)); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, username); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); len = sizeof (resp_buf); val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_INVALID_METHOD); assert (len > 0); /* Unknown attribute */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); val = stun_message_append_string (&req, 0x666, "The evil unknown attribute!"); assert (val == STUN_MESSAGE_RETURN_SUCCESS); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, username); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); valid = stun_agent_validate (&agent, &req, req_buf, rlen, stun_agent_default_validater, validater_data); assert (valid == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE); /* Unauthenticated message */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); rlen = stun_agent_finish_message (&agent, &req, NULL, 0); assert (rlen > 0); valid = stun_agent_validate (&agent, &req, req_buf, rlen, stun_agent_default_validater, validater_data); assert (valid == STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST); /* No username */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); valid = stun_agent_validate (&agent, &req, req_buf, rlen, stun_agent_default_validater, validater_data); assert (valid == STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST); assert (stun_usage_ice_conncheck_priority (&req) == 0); assert (stun_usage_ice_conncheck_use_candidate (&req) == false); /* Good message */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); val = stun_message_append32 (&req, STUN_ATTRIBUTE_PRIORITY, 0x12345678); assert (val == STUN_MESSAGE_RETURN_SUCCESS); val = stun_message_append_flag (&req, STUN_ATTRIBUTE_USE_CANDIDATE); assert (val == STUN_MESSAGE_RETURN_SUCCESS); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, (char*) ufrag); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); len = sizeof (resp_buf); val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_SUCCESS); assert (len > 0); assert (stun_agent_validate (&agent, &resp, resp_buf, len, stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS); assert (stun_message_get_class (&resp) == STUN_RESPONSE); assert (stun_usage_ice_conncheck_priority (&req) == 0x12345678); assert (stun_usage_ice_conncheck_use_candidate (&req) == true); /* Invalid socket address */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, (char *) ufrag); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); addr.ip4.sin_family = AF_UNSPEC; len = sizeof (resp_buf); val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_INVALID_ADDRESS); assert (len == 0); addr.ip4.sin_family = AF_INET; /* Lost role conflict */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLING, tie + 1); assert (val == STUN_MESSAGE_RETURN_SUCCESS); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, (char *) ufrag); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); len = sizeof (resp_buf); control = true; val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_ROLE_CONFLICT); assert (len > 0); assert (control == false); assert (stun_agent_validate (&agent, &resp, resp_buf, len, stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS); assert (stun_message_get_class (&resp) == STUN_RESPONSE); /* Won role conflict */ assert (stun_agent_init_request (&agent, &req, req_buf, sizeof(req_buf), STUN_BINDING)); val = stun_message_append64 (&req, STUN_ATTRIBUTE_ICE_CONTROLLED, tie - 1); assert (val == STUN_MESSAGE_RETURN_SUCCESS); val = stun_message_append_string (&req, STUN_ATTRIBUTE_USERNAME, (char *) ufrag); assert (val == STUN_MESSAGE_RETURN_SUCCESS); rlen = stun_agent_finish_message (&agent, &req, pass, pass_len); assert (rlen > 0); len = sizeof (resp_buf); control = false; val2 = stun_usage_ice_conncheck_create_reply (&agent, &req, &resp, resp_buf, &len, &addr.storage, sizeof (addr.ip4), &control, tie, STUN_USAGE_ICE_COMPATIBILITY_RFC5245); assert (val2 == STUN_USAGE_ICE_RETURN_SUCCESS); assert (len > 0); assert (control == false); assert (stun_agent_validate (&agent, &resp, resp_buf, len, stun_agent_default_validater, validater_data) == STUN_VALIDATION_SUCCESS); assert (stun_message_get_class (&resp) == STUN_ERROR); stun_message_find_error (&resp, &code); assert (code == STUN_ERROR_ROLE_CONFLICT); return 0; }
StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg, const uint8_t *buffer, size_t buffer_len, StunMessageIntegrityValidate validater, void * validater_data) { StunTransactionId msg_id; uint32_t fpr; uint32_t crc32; int len; uint8_t *username = NULL; uint16_t username_len; uint8_t *key = NULL; size_t key_len; uint8_t *hash; uint8_t sha[20]; uint16_t hlen; int sent_id_idx = -1; uint16_t unknown; int error_code; int ignore_credentials = 0; uint8_t long_term_key[16]; bool long_term_key_valid = FALSE; len = stun_message_validate_buffer_length (buffer, buffer_len); if (len == STUN_MESSAGE_BUFFER_INVALID) { return STUN_VALIDATION_NOT_STUN; } else if (len == STUN_MESSAGE_BUFFER_INCOMPLETE) { return STUN_VALIDATION_INCOMPLETE_STUN; } else if (len != (int) buffer_len) { return STUN_VALIDATION_NOT_STUN; } msg->buffer = (uint8_t *) buffer; msg->buffer_len = buffer_len; msg->agent = agent; msg->key = NULL; msg->key_len = 0; msg->long_term_valid = FALSE; /* TODO: reject it or not ? */ if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 || agent->compatibility == STUN_COMPATIBILITY_WLM2009) && !stun_message_has_cookie (msg)) { stun_debug ("STUN demux error: no cookie!\n"); return STUN_VALIDATION_BAD_REQUEST; } if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 || agent->compatibility == STUN_COMPATIBILITY_WLM2009) && agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) { /* Looks for FINGERPRINT */ if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug ("STUN demux error: no FINGERPRINT attribute!\n"); return STUN_VALIDATION_BAD_REQUEST; } /* Checks FINGERPRINT */ crc32 = stun_fingerprint (msg->buffer, stun_message_length (msg), agent->compatibility == STUN_COMPATIBILITY_WLM2009); fpr = ntohl (fpr); if (fpr != crc32) { stun_debug ("STUN demux error: bad fingerprint: 0x%08x," " expected: 0x%08x!\n", fpr, crc32); return STUN_VALIDATION_BAD_REQUEST; } stun_debug ("STUN demux: OK!\n"); } if (stun_message_get_class (msg) == STUN_RESPONSE || stun_message_get_class (msg) == STUN_ERROR) { stun_message_id (msg, msg_id); for (sent_id_idx = 0; sent_id_idx < STUN_AGENT_MAX_SAVED_IDS; sent_id_idx++) { if (agent->sent_ids[sent_id_idx].valid == TRUE && agent->sent_ids[sent_id_idx].method == stun_message_get_method (msg) && memcmp (msg_id, agent->sent_ids[sent_id_idx].id, sizeof(StunTransactionId)) == 0) { key = agent->sent_ids[sent_id_idx].key; key_len = agent->sent_ids[sent_id_idx].key_len; memcpy (long_term_key, agent->sent_ids[sent_id_idx].long_term_key, sizeof(long_term_key)); long_term_key_valid = agent->sent_ids[sent_id_idx].long_term_valid; break; } } if (sent_id_idx == STUN_AGENT_MAX_SAVED_IDS) { return STUN_VALIDATION_UNMATCHED_RESPONSE; } } ignore_credentials = (agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) || (stun_message_get_class (msg) == STUN_ERROR && stun_message_find_error (msg, &error_code) == STUN_MESSAGE_RETURN_SUCCESS && (error_code == 400 || error_code == 401)) || (stun_message_get_class (msg) == STUN_INDICATION && (agent->usage_flags & STUN_AGENT_USAGE_NO_INDICATION_AUTH)); if (key == NULL && ignore_credentials == 0 && (stun_message_get_class (msg) == STUN_REQUEST || stun_message_get_class (msg) == STUN_INDICATION) && (((agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS) && (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) || !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY))) || ((agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) && stun_message_get_class (msg) == STUN_REQUEST && (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) || !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) || !stun_message_has_attribute (msg, STUN_ATTRIBUTE_NONCE) || !stun_message_has_attribute (msg, STUN_ATTRIBUTE_REALM))) || ((agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) == 0 && stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) && !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY)))) { return STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST; } if (stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) && ((key == NULL && ignore_credentials == 0) || (agent->usage_flags & STUN_AGENT_USAGE_FORCE_VALIDATER))) { username_len = 0; username = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_USERNAME, &username_len); if (validater == NULL || validater (agent, msg, username, username_len, &key, &key_len, validater_data) == FALSE) { return STUN_VALIDATION_UNAUTHORIZED; } } if (ignore_credentials == 0 && key != NULL && key_len > 0) { hash = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, &hlen); if (hash) { /* We must give the size from start to the end of the attribute because you might have a FINGERPRINT attribute after it... */ if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) { uint8_t *realm = NULL; uint8_t *username = NULL; uint16_t realm_len; uint16_t username_len; uint8_t md5[16]; if (long_term_key_valid) { memcpy (md5, long_term_key, sizeof (md5)); } else { realm = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_REALM, &realm_len); username = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_USERNAME, &username_len); if (username == NULL || realm == NULL) { return STUN_VALIDATION_UNAUTHORIZED; } stun_hash_creds (realm, realm_len, username, username_len, key, key_len, md5); } memcpy (msg->long_term_key, md5, sizeof(md5)); msg->long_term_valid = TRUE; if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) { stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer, sha, md5, sizeof(md5), TRUE); } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) { stun_sha1 (msg->buffer, hash + 20 - msg->buffer, stun_message_length (msg) - 20, sha, md5, sizeof(md5), TRUE); } else { stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer, sha, md5, sizeof(md5), FALSE); } } else { if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) { stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer, sha, key, key_len, TRUE); } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) { stun_sha1 (msg->buffer, hash + 20 - msg->buffer, stun_message_length (msg) - 20, sha, key, key_len, TRUE); } else { stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer, sha, key, key_len, FALSE); } } stun_debug (" Message HMAC-SHA1 fingerprint:"); stun_debug ("\nkey : "); stun_debug_bytes (key, key_len); stun_debug ("\n expected: "); stun_debug_bytes (sha, sizeof (sha)); stun_debug ("\n received: "); stun_debug_bytes (hash, sizeof (sha)); stun_debug ("\n"); if (memcmp (sha, hash, sizeof (sha))) { stun_debug ("STUN auth error: SHA1 fingerprint mismatch!\n"); return STUN_VALIDATION_UNAUTHORIZED; } stun_debug ("STUN auth: OK!\n"); msg->key = key; msg->key_len = key_len; } else if (!(stun_message_get_class (msg) == STUN_ERROR && stun_message_find_error (msg, &error_code) == STUN_MESSAGE_RETURN_SUCCESS && (error_code == 400 || error_code == 401))) { stun_debug ("STUN auth error: No message integrity attribute!\n"); return STUN_VALIDATION_UNAUTHORIZED; } } if (sent_id_idx != -1 && sent_id_idx < STUN_AGENT_MAX_SAVED_IDS) { agent->sent_ids[sent_id_idx].valid = FALSE; } if (stun_agent_find_unknowns (agent, msg, &unknown, 1) > 0) { if (stun_message_get_class (msg) == STUN_REQUEST) return STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE; else return STUN_VALIDATION_UNKNOWN_ATTRIBUTE; } return STUN_VALIDATION_SUCCESS; }
StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg, struct sockaddr *relay_addr, socklen_t *relay_addrlen, struct sockaddr *addr, socklen_t *addrlen, struct sockaddr *alternate_server, socklen_t *alternate_server_len, uint32_t *bandwidth, uint32_t *lifetime, StunUsageTurnCompatibility compatibility) { int val, code = -1; StunUsageTurnReturn ret = STUN_USAGE_TURN_RETURN_RELAY_SUCCESS; if (stun_message_get_method (msg) != STUN_ALLOCATE) return STUN_USAGE_TURN_RETURN_INVALID; switch (stun_message_get_class (msg)) { case STUN_REQUEST: case STUN_INDICATION: return STUN_USAGE_TURN_RETURN_INVALID; case STUN_RESPONSE: break; case STUN_ERROR: if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) { /* missing ERROR-CODE: ignore message */ return STUN_USAGE_TURN_RETURN_INVALID; } /* NOTE: currently we ignore unauthenticated messages if the context * is authenticated, for security reasons. */ stun_debug (" STUN error message received (code: %d)\n", code); /* ALTERNATE-SERVER mechanism */ if ((code / 100) == 3) { if (alternate_server && alternate_server_len) { if (stun_message_find_addr (msg, STUN_ATTRIBUTE_ALTERNATE_SERVER, alternate_server, alternate_server_len) != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute\n"); return STUN_USAGE_TURN_RETURN_ERROR; } } else { if (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_ALTERNATE_SERVER)) { stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute\n"); return STUN_USAGE_TURN_RETURN_ERROR; } } stun_debug ("Found alternate server\n"); return STUN_USAGE_TURN_RETURN_ALTERNATE_SERVER; } return STUN_USAGE_TURN_RETURN_ERROR; } stun_debug ("Received %u-bytes STUN message\n", stun_message_length (msg)); if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_DRAFT9) { val = stun_message_find_xor_addr (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen); if (val == STUN_MESSAGE_RETURN_SUCCESS) ret = STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS; val = stun_message_find_xor_addr (msg, STUN_ATTRIBUTE_RELAY_ADDRESS, relay_addr, relay_addrlen); if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug (" No RELAYED-ADDRESS: %d\n", val); return STUN_USAGE_TURN_RETURN_ERROR; } } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_GOOGLE) { val = stun_message_find_addr (msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, relay_addr, relay_addrlen); if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug (" No MAPPED-ADDRESS: %d\n", val); return STUN_USAGE_TURN_RETURN_ERROR; } } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_MSN) { val = stun_message_find_addr (msg, STUN_ATTRIBUTE_MSN_MAPPED_ADDRESS, addr, addrlen); if (val == STUN_MESSAGE_RETURN_SUCCESS) ret = STUN_USAGE_TURN_RETURN_MAPPED_SUCCESS; val = stun_message_find_addr (msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, relay_addr, relay_addrlen); if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug (" No MAPPED-ADDRESS: %d\n", val); return STUN_USAGE_TURN_RETURN_ERROR; } } stun_message_find32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime); stun_message_find32 (msg, STUN_ATTRIBUTE_BANDWIDTH, bandwidth); stun_debug (" Mapped address found!\n"); return ret; }
StunUsageIceReturn stun_usage_ice_conncheck_process (StunMessage *msg, struct sockaddr *addr, socklen_t *addrlen, StunUsageIceCompatibility compatibility) { int code = -1; StunMessageReturn val; if (stun_message_get_method (msg) != STUN_BINDING) return STUN_USAGE_ICE_RETURN_INVALID; switch (stun_message_get_class (msg)) { case STUN_REQUEST: case STUN_INDICATION: return STUN_USAGE_ICE_RETURN_INVALID; case STUN_RESPONSE: break; case STUN_ERROR: if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) { /* missing ERROR-CODE: ignore message */ return STUN_USAGE_ICE_RETURN_INVALID; } if (code == STUN_ERROR_ROLE_CONFLICT) return STUN_USAGE_ICE_RETURN_ROLE_CONFLICT; /* NOTE: currently we ignore unauthenticated messages if the context * is authenticated, for security reasons. */ stun_debug (" STUN error message received (code: %d)\n", code); return STUN_USAGE_ICE_RETURN_ERROR; } stun_debug ("Received %u-bytes STUN message\n", stun_message_length (msg)); if (compatibility == STUN_USAGE_ICE_COMPATIBILITY_MSN) { StunTransactionId transid; uint32_t magic_cookie; stun_message_id (msg, transid); magic_cookie = *((uint32_t *) transid); val = stun_message_find_xor_addr_full (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen, htonl (magic_cookie)); } else { val = stun_message_find_xor_addr (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, addr, addrlen); } if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug (" No XOR-MAPPED-ADDRESS: %d\n", val); val = stun_message_find_addr (msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, addr, addrlen); if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug (" No MAPPED-ADDRESS: %d\n", val); return STUN_USAGE_ICE_RETURN_NO_MAPPED_ADDRESS; } } stun_debug ("Mapped address found!\n"); return STUN_USAGE_ICE_RETURN_SUCCESS; }
StunUsageBindReturn stun_usage_bind_process (StunMessage *msg, struct sockaddr *addr, socklen_t *addrlen, struct sockaddr *alternate_server, socklen_t *alternate_server_len) { int code = -1; StunMessageReturn val; if (stun_message_get_method (msg) != STUN_BINDING) return STUN_USAGE_BIND_RETURN_INVALID; switch (stun_message_get_class (msg)) { case STUN_REQUEST: case STUN_INDICATION: return STUN_USAGE_BIND_RETURN_INVALID; case STUN_RESPONSE: break; case STUN_ERROR: if (stun_message_find_error (msg, &code) != STUN_MESSAGE_RETURN_SUCCESS) { /* missing ERROR-CODE: ignore message */ return STUN_USAGE_BIND_RETURN_INVALID; } /* NOTE: currently we ignore unauthenticated messages if the context * is authenticated, for security reasons. */ stun_debug (" STUN error message received (code: %d)", code); /* ALTERNATE-SERVER mechanism */ if ((code / 100) == 3) { if (alternate_server && alternate_server_len) { if (stun_message_find_addr (msg, STUN_ATTRIBUTE_ALTERNATE_SERVER, (struct sockaddr_storage *) alternate_server, alternate_server_len) != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute"); return STUN_USAGE_BIND_RETURN_ERROR; } } else { if (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_ALTERNATE_SERVER)) { stun_debug (" Unexpectedly missing ALTERNATE-SERVER attribute"); return STUN_USAGE_BIND_RETURN_ERROR; } } stun_debug ("Found alternate server"); return STUN_USAGE_BIND_RETURN_ALTERNATE_SERVER; } return STUN_USAGE_BIND_RETURN_ERROR; default: /* Fall through. */ break; } stun_debug ("Received %u-bytes STUN message", stun_message_length (msg)); val = stun_message_find_xor_addr (msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, (struct sockaddr_storage *)addr, addrlen); if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug (" No XOR-MAPPED-ADDRESS: %d", val); val = stun_message_find_addr (msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, (struct sockaddr_storage *)addr, addrlen); if (val != STUN_MESSAGE_RETURN_SUCCESS) { stun_debug (" No MAPPED-ADDRESS: %d", val); return STUN_USAGE_BIND_RETURN_ERROR; } } stun_debug (" Mapped address found!"); return STUN_USAGE_BIND_RETURN_SUCCESS; }