michael@0: /* michael@0: Copyright (c) 2007, Adobe Systems, Incorporated michael@0: All rights reserved. michael@0: michael@0: Redistribution and use in source and binary forms, with or without michael@0: modification, are permitted provided that the following conditions are michael@0: met: michael@0: michael@0: * Redistributions of source code must retain the above copyright michael@0: notice, this list of conditions and the following disclaimer. michael@0: michael@0: * Redistributions in binary form must reproduce the above copyright michael@0: notice, this list of conditions and the following disclaimer in the michael@0: documentation and/or other materials provided with the distribution. michael@0: michael@0: * Neither the name of Adobe Systems, Network Resonance nor the names of its michael@0: contributors may be used to endorse or promote products derived from michael@0: this software without specific prior written permission. michael@0: michael@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: michael@0: michael@0: static char *RCSSTRING __UNUSED__="$Id: stun_proc.c,v 1.2 2008/04/28 18:21:30 ekr Exp $"; michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #ifdef WIN32 michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #else /* UNIX */ michael@0: #include michael@0: #endif /* end UNIX */ michael@0: #include michael@0: michael@0: #include "stun.h" michael@0: #include "stun_reg.h" michael@0: #include "registry.h" michael@0: michael@0: static int michael@0: nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res); michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 7.3 */ michael@0: int michael@0: nr_stun_receive_message(nr_stun_message *req, nr_stun_message *msg) michael@0: { michael@0: int _status; michael@0: nr_stun_message_attribute *attr; michael@0: michael@0: #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE michael@0: /* if this message was generated by an RFC 3489 impementation, michael@0: * the call to nr_is_stun_message will fail, so skip that michael@0: * check and puke elsewhere if the message can't be decoded */ michael@0: if (msg->header.magic_cookie == NR_STUN_MAGIC_COOKIE michael@0: || msg->header.magic_cookie == NR_STUN_MAGIC_COOKIE2) { michael@0: #endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */ michael@0: if (!nr_is_stun_message(msg->buffer, msg->length)) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Not a STUN message"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE michael@0: } michael@0: #endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */ michael@0: michael@0: if (req == 0) { michael@0: if (NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_REQUEST) { michael@0: r_log(NR_LOG_STUN,LOG_WARNING,"Illegal message type: %03x", msg->header.type); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: } michael@0: else { michael@0: if (NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_RESPONSE michael@0: && NR_STUN_GET_TYPE_CLASS(msg->header.type) != NR_CLASS_ERROR_RESPONSE) { michael@0: r_log(NR_LOG_STUN,LOG_WARNING,"Illegal message class: %03x", msg->header.type); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: michael@0: if (NR_STUN_GET_TYPE_METHOD(req->header.type) != NR_STUN_GET_TYPE_METHOD(msg->header.type)) { michael@0: r_log(NR_LOG_STUN,LOG_WARNING,"Inconsistent message method: %03x expected %03x", msg->header.type, req->header.type); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: michael@0: if (nr_stun_different_transaction(msg->buffer, msg->length, req)) { michael@0: r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized STUN transaction"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: } michael@0: michael@0: switch (msg->header.magic_cookie) { michael@0: case NR_STUN_MAGIC_COOKIE: michael@0: /* basically draft-ietf-behave-rfc3489bis-10.txt S 6 rules */ michael@0: michael@0: if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_FINGERPRINT, &attr) michael@0: && !attr->u.fingerprint.valid) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Invalid fingerprint"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: michael@0: break; michael@0: michael@0: #ifdef USE_STUND_0_96 michael@0: case NR_STUN_MAGIC_COOKIE2: michael@0: /* nothing to check in this case */ michael@0: break; michael@0: #endif /* USE_STUND_0_96 */ michael@0: michael@0: default: michael@0: #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE michael@0: /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */ michael@0: #else michael@0: #ifdef NDEBUG michael@0: /* in deployment builds we should always see a recognized magic cookie */ michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Missing Magic Cookie"); michael@0: ABORT(R_REJECTED); michael@0: #else michael@0: /* ignore this condition because sometimes we like to pretend we're michael@0: * a server talking to old clients and their messages don't contain michael@0: * a magic cookie at all but rather the magic cookie field is part michael@0: * of their ID and therefore random */ michael@0: #endif /* NDEBUG */ michael@0: #endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */ michael@0: break; michael@0: } michael@0: michael@0: _status=0; michael@0: abort: michael@0: return _status; michael@0: } michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.1 */ michael@0: int michael@0: nr_stun_process_request(nr_stun_message *req, nr_stun_message *res) michael@0: { michael@0: int _status; michael@0: #ifdef USE_STUN_PEDANTIC michael@0: int r; michael@0: nr_stun_attr_unknown_attributes unknown_attributes = { { 0 } }; michael@0: nr_stun_message_attribute *attr; michael@0: michael@0: if (req->comprehension_required_unknown_attributes > 0) { michael@0: nr_stun_form_error_response(req, res, 420, "Unknown Attributes"); michael@0: michael@0: TAILQ_FOREACH(attr, &req->attributes, entry) { michael@0: if (attr->name == 0) { michael@0: /* unrecognized attribute */ michael@0: michael@0: /* should never happen, but truncate if it ever were to occur */ michael@0: if (unknown_attributes.num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES) michael@0: break; michael@0: michael@0: unknown_attributes.attribute[unknown_attributes.num_attributes++] = attr->type; michael@0: } michael@0: } michael@0: michael@0: assert(req->comprehension_required_unknown_attributes + req->comprehension_optional_unknown_attributes == unknown_attributes.num_attributes); michael@0: michael@0: if ((r=nr_stun_message_add_unknown_attributes_attribute(res, &unknown_attributes))) michael@0: ABORT(R_ALREADY); michael@0: michael@0: ABORT(R_ALREADY); michael@0: } michael@0: #endif /* USE_STUN_PEDANTIC */ michael@0: michael@0: _status=0; michael@0: #ifdef USE_STUN_PEDANTIC michael@0: abort: michael@0: #endif /* USE_STUN_PEDANTIC */ michael@0: return _status; michael@0: } michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.2 */ michael@0: int michael@0: nr_stun_process_indication(nr_stun_message *ind) michael@0: { michael@0: int _status; michael@0: #ifdef USE_STUN_PEDANTIC michael@0: michael@0: if (ind->comprehension_required_unknown_attributes > 0) michael@0: ABORT(R_REJECTED); michael@0: #endif /* USE_STUN_PEDANTIC */ michael@0: michael@0: _status=0; michael@0: #ifdef USE_STUN_PEDANTIC michael@0: abort: michael@0: #endif /* USE_STUN_PEDANTIC */ michael@0: return _status; michael@0: } michael@0: michael@0: /* RFC5389 S 7.3.3, except that we *also* allow a MAPPED_ADDRESS michael@0: to compensate for a bug in Google's STUN server where it michael@0: always returns MAPPED_ADDRESS. michael@0: michael@0: Mozilla bug: 888274. michael@0: */ michael@0: int michael@0: nr_stun_process_success_response(nr_stun_message *res) michael@0: { michael@0: int _status; michael@0: michael@0: #ifdef USE_STUN_PEDANTIC michael@0: if (res->comprehension_required_unknown_attributes > 0) michael@0: ABORT(R_REJECTED); michael@0: #endif /* USE_STUN_PEDANTIC */ michael@0: michael@0: if (NR_STUN_GET_TYPE_METHOD(res->header.type) == NR_METHOD_BINDING) { michael@0: if (! nr_stun_message_has_attribute(res, NR_STUN_ATTR_XOR_MAPPED_ADDRESS, 0) && michael@0: ! nr_stun_message_has_attribute(res, NR_STUN_ATTR_MAPPED_ADDRESS, 0)) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Missing XOR-MAPPED-ADDRESS and MAPPED_ADDRESS"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: } michael@0: michael@0: _status=0; michael@0: abort: michael@0: return _status; michael@0: } michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 7.3.4 */ michael@0: int michael@0: nr_stun_process_error_response(nr_stun_message *res, UINT2 *error_code) michael@0: { michael@0: int _status; michael@0: nr_stun_message_attribute *attr; michael@0: michael@0: if (res->comprehension_required_unknown_attributes > 0) { michael@0: ABORT(R_REJECTED); michael@0: } michael@0: michael@0: if (! nr_stun_message_has_attribute(res, NR_STUN_ATTR_ERROR_CODE, &attr)) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Missing ERROR-CODE"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: michael@0: *error_code = attr->u.error_code.number; michael@0: michael@0: switch (attr->u.error_code.number / 100) { michael@0: case 3: michael@0: /* If the error code is 300 through 399, the client SHOULD consider michael@0: * the transaction as failed unless the ALTERNATE-SERVER extension is michael@0: * being used. See Section 11. */ michael@0: michael@0: if (attr->u.error_code.number == 300) { michael@0: if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_ALTERNATE_SERVER, 0)) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Missing ALTERNATE-SERVER"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 11 */ michael@0: if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, 0)) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Missing MESSAGE-INTEGRITY"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: michael@0: ABORT(R_RETRY); michael@0: } michael@0: michael@0: ABORT(R_REJECTED); michael@0: break; michael@0: michael@0: case 4: michael@0: /* If the error code is 400 through 499, the client declares the michael@0: * transaction failed; in the case of 420 (Unknown Attribute), the michael@0: * response should contain a UNKNOWN-ATTRIBUTES attribute that gives michael@0: * additional information. */ michael@0: if (attr->u.error_code.number == 420) michael@0: ABORT(R_REJECTED); michael@0: michael@0: /* it may be possible to restart given the info that was received in michael@0: * this response, so retry */ michael@0: ABORT(R_RETRY); michael@0: break; michael@0: michael@0: case 5: michael@0: /* If the error code is 500 through 599, the client MAY resend the michael@0: * request; clients that do so MUST limit the number of times they do michael@0: * this. */ michael@0: /* let the retransmit mechanism handle resending the request */ michael@0: break; michael@0: michael@0: default: michael@0: ABORT(R_REJECTED); michael@0: break; michael@0: } michael@0: michael@0: /* the spec says: "The client then does any processing specified by the authentication michael@0: * mechanism (see Section 10). This may result in a new transaction michael@0: * attempt." -- but this is handled already elsewhere, so needn't be repeated michael@0: * in this function */ michael@0: michael@0: _status=0; michael@0: abort: michael@0: return _status; michael@0: } michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 10.1.2 */ michael@0: int michael@0: nr_stun_receive_request_or_indication_short_term_auth(nr_stun_message *msg, michael@0: nr_stun_message *res) michael@0: { michael@0: int _status; michael@0: nr_stun_message_attribute *attr; michael@0: michael@0: switch (msg->header.magic_cookie) { michael@0: default: michael@0: /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */ michael@0: /* drop thru */ michael@0: case NR_STUN_MAGIC_COOKIE: michael@0: if (!nr_stun_message_has_attribute(msg, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) { michael@0: nr_stun_form_error_response(msg, res, 400, "Missing MESSAGE-INTEGRITY"); michael@0: ABORT(R_ALREADY); michael@0: } michael@0: michael@0: if (!nr_stun_message_has_attribute(msg, NR_STUN_ATTR_USERNAME, 0)) { michael@0: nr_stun_form_error_response(msg, res, 400, "Missing USERNAME"); michael@0: ABORT(R_ALREADY); michael@0: } michael@0: michael@0: if (attr->u.message_integrity.unknown_user) { michael@0: nr_stun_form_error_response(msg, res, 401, "Unrecognized USERNAME"); michael@0: ABORT(R_ALREADY); michael@0: } michael@0: michael@0: if (!attr->u.message_integrity.valid) { michael@0: nr_stun_form_error_response(msg, res, 401, "Bad MESSAGE-INTEGRITY"); michael@0: ABORT(R_ALREADY); michael@0: } michael@0: michael@0: break; michael@0: michael@0: #ifdef USE_STUND_0_96 michael@0: case NR_STUN_MAGIC_COOKIE2: michael@0: /* nothing to check in this case */ michael@0: break; michael@0: #endif /* USE_STUND_0_96 */ michael@0: } michael@0: michael@0: _status=0; michael@0: abort: michael@0: return _status; michael@0: } michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 10.1.3 */ michael@0: int michael@0: nr_stun_receive_response_short_term_auth(nr_stun_message *res) michael@0: { michael@0: int _status; michael@0: nr_stun_message_attribute *attr; michael@0: michael@0: switch (res->header.magic_cookie) { michael@0: default: michael@0: /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */ michael@0: /* drop thru */ michael@0: case NR_STUN_MAGIC_COOKIE: michael@0: if (!nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Missing MESSAGE-INTEGRITY"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: michael@0: if (!attr->u.message_integrity.valid) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Bad MESSAGE-INTEGRITY"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: michael@0: break; michael@0: michael@0: #ifdef USE_STUND_0_96 michael@0: case NR_STUN_MAGIC_COOKIE2: michael@0: /* nothing to check in this case */ michael@0: break; michael@0: #endif /* USE_STUND_0_96 */ michael@0: } michael@0: michael@0: _status=0; michael@0: abort: michael@0: return _status; michael@0: } michael@0: michael@0: static int michael@0: nr_stun_add_realm_and_nonce(int new_nonce, nr_stun_server_client *clnt, nr_stun_message *res) michael@0: { michael@0: int r,_status; michael@0: char *realm = 0; michael@0: char *nonce; michael@0: UINT2 size; michael@0: michael@0: if ((r=NR_reg_alloc_string(NR_STUN_REG_PREF_SERVER_REALM, &realm))) michael@0: ABORT(r); michael@0: michael@0: if ((r=nr_stun_message_add_realm_attribute(res, realm))) michael@0: ABORT(r); michael@0: michael@0: if (clnt) { michael@0: if (strlen(clnt->nonce) < 1) michael@0: new_nonce = 1; michael@0: michael@0: if (new_nonce) { michael@0: if (NR_reg_get_uint2(NR_STUN_REG_PREF_SERVER_NONCE_SIZE, &size)) michael@0: size = 48; michael@0: michael@0: if (size > (sizeof(clnt->nonce) - 1)) michael@0: size = sizeof(clnt->nonce) - 1; michael@0: michael@0: nr_random_alphanum(clnt->nonce, size); michael@0: clnt->nonce[size] = '\0'; michael@0: } michael@0: michael@0: nonce = clnt->nonce; michael@0: } michael@0: else { michael@0: /* user is not known, so use a bogus nonce since there's no way to michael@0: * store a good nonce with the client-specific data -- this nonce michael@0: * will be recognized as stale if the client attempts another michael@0: * request */ michael@0: nonce = "STALE"; michael@0: } michael@0: michael@0: if ((r=nr_stun_message_add_nonce_attribute(res, nonce))) michael@0: ABORT(r); michael@0: michael@0: _status=0; michael@0: abort: michael@0: #ifdef USE_TURN michael@0: assert(_status == 0); /* TODO: !nn! cleanup after I reimplmement TURN */ michael@0: #endif michael@0: RFREE(realm); michael@0: return _status; michael@0: } michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 10.2.1 - 10.2.2 */ michael@0: int michael@0: nr_stun_receive_request_long_term_auth(nr_stun_message *req, nr_stun_server_ctx *ctx, nr_stun_message *res) michael@0: { michael@0: int r,_status; michael@0: nr_stun_message_attribute *mi; michael@0: nr_stun_message_attribute *n; michael@0: nr_stun_server_client *clnt = 0; michael@0: michael@0: switch (req->header.magic_cookie) { michael@0: default: michael@0: /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */ michael@0: /* drop thru */ michael@0: case NR_STUN_MAGIC_COOKIE: michael@0: if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_USERNAME, 0)) { michael@0: nr_stun_form_error_response(req, res, 400, "Missing USERNAME"); michael@0: nr_stun_add_realm_and_nonce(0, 0, res); michael@0: ABORT(R_ALREADY); michael@0: } michael@0: michael@0: if ((r=nr_stun_get_message_client(ctx, req, &clnt))) { michael@0: nr_stun_form_error_response(req, res, 401, "Unrecognized USERNAME"); michael@0: nr_stun_add_realm_and_nonce(0, 0, res); michael@0: ABORT(R_ALREADY); michael@0: } michael@0: michael@0: if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_MESSAGE_INTEGRITY, &mi)) { michael@0: nr_stun_form_error_response(req, res, 401, "Missing MESSAGE-INTEGRITY"); michael@0: nr_stun_add_realm_and_nonce(0, clnt, res); michael@0: ABORT(R_ALREADY); michael@0: } michael@0: michael@0: assert(!mi->u.message_integrity.unknown_user); michael@0: michael@0: if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_REALM, 0)) { michael@0: nr_stun_form_error_response(req, res, 400, "Missing REALM"); michael@0: ABORT(R_ALREADY); michael@0: } michael@0: michael@0: if (!nr_stun_message_has_attribute(req, NR_STUN_ATTR_NONCE, &n)) { michael@0: nr_stun_form_error_response(req, res, 400, "Missing NONCE"); michael@0: ABORT(R_ALREADY); michael@0: } michael@0: michael@0: assert(sizeof(clnt->nonce) == sizeof(n->u.nonce)); michael@0: if (strncmp(clnt->nonce, n->u.nonce, sizeof(n->u.nonce))) { michael@0: nr_stun_form_error_response(req, res, 438, "Stale NONCE"); michael@0: nr_stun_add_realm_and_nonce(1, clnt, res); michael@0: ABORT(R_ALREADY); michael@0: } michael@0: michael@0: if (!mi->u.message_integrity.valid) { michael@0: nr_stun_form_error_response(req, res, 401, "Bad MESSAGE-INTEGRITY"); michael@0: nr_stun_add_realm_and_nonce(0, clnt, res); michael@0: ABORT(R_ALREADY); michael@0: } michael@0: michael@0: break; michael@0: michael@0: #ifdef USE_STUND_0_96 michael@0: case NR_STUN_MAGIC_COOKIE2: michael@0: /* nothing to do in this case */ michael@0: break; michael@0: #endif /* USE_STUND_0_96 */ michael@0: } michael@0: michael@0: _status=0; michael@0: abort: michael@0: michael@0: return _status; michael@0: } michael@0: michael@0: /* draft-ietf-behave-rfc3489bis-10.txt S 10.2.3 */ michael@0: int michael@0: nr_stun_receive_response_long_term_auth(nr_stun_message *res, nr_stun_client_ctx *ctx) michael@0: { michael@0: int _status; michael@0: nr_stun_message_attribute *attr; michael@0: michael@0: switch (res->header.magic_cookie) { michael@0: default: michael@0: /* in RFC 3489 there is no magic cookie, it's part of the transaction ID */ michael@0: /* drop thru */ michael@0: case NR_STUN_MAGIC_COOKIE: michael@0: if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_REALM, &attr)) { michael@0: RFREE(ctx->realm); michael@0: ctx->realm = r_strdup(attr->u.realm); michael@0: if (!ctx->realm) michael@0: ABORT(R_NO_MEMORY); michael@0: } michael@0: else { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Missing REALM"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: michael@0: if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_NONCE, &attr)) { michael@0: RFREE(ctx->nonce); michael@0: ctx->nonce = r_strdup(attr->u.nonce); michael@0: if (!ctx->nonce) michael@0: ABORT(R_NO_MEMORY); michael@0: } michael@0: else { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Missing NONCE"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: michael@0: if (nr_stun_message_has_attribute(res, NR_STUN_ATTR_MESSAGE_INTEGRITY, &attr)) { michael@0: if (!attr->u.message_integrity.valid) { michael@0: r_log(NR_LOG_STUN, LOG_WARNING, "Bad MESSAGE-INTEGRITY"); michael@0: ABORT(R_REJECTED); michael@0: } michael@0: } michael@0: michael@0: break; michael@0: michael@0: #ifdef USE_STUND_0_96 michael@0: case NR_STUN_MAGIC_COOKIE2: michael@0: /* nothing to check in this case */ michael@0: break; michael@0: #endif /* USE_STUND_0_96 */ michael@0: } michael@0: michael@0: _status=0; michael@0: abort: michael@0: return _status; michael@0: } michael@0: