Use SIPS URIs in Contact headers when appropriate.

RFC 3261 sections 8.1.1.8 and 12.1.1 dictate specific
scenarios when we are required to use SIPS URIs in Contact
headers. Asterisk's non-compliance with this could actually
cause calls to get dropped when communicating with clients
that are strict about checking the Contact header.

Both of the SIP stacks in Asterisk suffered from this issue.
This changeset corrects the behavior in chan_sip.

ASTERISK-24646 #close
Reported by Stephan Eisvogel

Review: https://reviewboard.asterisk.org/r/4346
........

Merged revisions 431423 from http://svn.asterisk.org/svn/asterisk/branches/11


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/13@431424 65c4cc65-6c06-0410-ace0-fbb531ad65f3
changes/43/43/1
Mark Michelson 10 years ago
parent b8ea23b0d1
commit 22fc3359da

@ -1446,7 +1446,7 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const st
static void set_destination(struct sip_pvt *p, const char *uri); static void set_destination(struct sip_pvt *p, const char *uri);
static void add_date(struct sip_request *req); static void add_date(struct sip_request *req);
static void add_expires(struct sip_request *req, int expires); static void add_expires(struct sip_request *req, int expires);
static void build_contact(struct sip_pvt *p); static void build_contact(struct sip_pvt *p, struct sip_request *req, int incoming);
/*------Request handling functions */ /*------Request handling functions */
static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int *recount, int *nounlock); static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int *recount, int *nounlock);
@ -13838,22 +13838,110 @@ static void extract_uri(struct sip_pvt *p, struct sip_request *req)
if (!ast_strlen_zero(c)) { if (!ast_strlen_zero(c)) {
ast_string_field_set(p, uri, c); ast_string_field_set(p, uri, c);
} }
}
/*!
* \brief Determine if, as a UAS, we need to use a SIPS Contact.
*
* This uses the rules defined in RFC 3261 section 12.1.1 to
* determine if a SIPS URI should be used as the Contact header
* when responding to incoming SIP requests.
*
* \param req The incoming SIP request
* \retval 0 SIPS is not required
* \retval 1 SIPS is required
*/
static int uas_sips_contact(struct sip_request *req)
{
const char *record_route = sip_get_header(req, "Record-Route");
if (!strncmp(REQ_OFFSET_TO_STR(req, rlpart2), "sips:", 5)) {
return 1;
}
if (record_route) {
char *record_route_uri = get_in_brackets(ast_strdupa(record_route));
if (!strncmp(record_route_uri, "sips:", 5)) {
return 1;
}
} else {
const char *contact = sip_get_header(req, "Contact");
char *contact_uri = get_in_brackets(ast_strdupa(contact));
if (!strncmp(contact_uri, "sips:", 5)) {
return 1;
}
}
return 0;
}
/*!
* \brief Determine if, as a UAC, we need to use a SIPS Contact.
*
* This uses the rules defined in RFC 3621 section 8.1.1.8 to
* determine if a SIPS URI should be used as the Contact header
* on our outgoing request.
*
* \param req The outgoing SIP request
* \retval 0 SIPS is not required
* \retval 1 SIPS is required
*/
static int uac_sips_contact(struct sip_request *req)
{
const char *route = sip_get_header(req, "Route");
if (!strncmp(REQ_OFFSET_TO_STR(req, rlpart2), "sips:", 5)) {
return 1;
}
if (route) {
char *route_uri = get_in_brackets(ast_strdupa(route));
if (!strncmp(route_uri, "sips:", 5)) {
return 1;
}
}
return 0;
} }
/*! \brief Build contact header - the contact header we send out */ /*!
static void build_contact(struct sip_pvt *p) * \brief Build contact header
*
* This is the Contact header that we send out in SIP requests and responses
* involving this sip_pvt.
*
* The incoming parameter is used to tell if we are building the request parameter
* is an incoming SIP request that we are building the Contact header in response to,
* or if the req parameter is an outbound SIP request that we will later be adding
* the Contact header to.
*
* \param p The sip_pvt where the built Contact will be saved.
* \param req The request that triggered the creation of a Contact header.
* \param incoming Indicates if the Contact header is being created for a response to an incoming request
*/
static void build_contact(struct sip_pvt *p, struct sip_request *req, int incoming)
{ {
char tmp[SIPBUFSIZE]; char tmp[SIPBUFSIZE];
char *user = ast_uri_encode(p->exten, tmp, sizeof(tmp), ast_uri_sip_user); char *user = ast_uri_encode(p->exten, tmp, sizeof(tmp), ast_uri_sip_user);
int use_sips;
if (incoming) {
use_sips = uas_sips_contact(req);
} else {
use_sips = uac_sips_contact(req);
}
if (p->socket.type == AST_TRANSPORT_UDP) { if (p->socket.type == AST_TRANSPORT_UDP) {
ast_string_field_build(p, our_contact, "<sip:%s%s%s>", user, ast_string_field_build(p, our_contact, "<%s:%s%s%s>", use_sips ? "sips" : "sip",
ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify_remote(&p->ourip)); user, ast_strlen_zero(user) ? "" : "@",
ast_sockaddr_stringify_remote(&p->ourip));
} else { } else {
ast_string_field_build(p, our_contact, "<sip:%s%s%s;transport=%s>", user, ast_string_field_build(p, our_contact, "<%s:%s%s%s;transport=%s>",
ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify_remote(&p->ourip), use_sips ? "sips" : "sip", user, ast_strlen_zero(user) ? "" : "@",
sip_get_transport(p->socket.type)); ast_sockaddr_stringify_remote(&p->ourip), sip_get_transport(p->socket.type));
} }
} }
@ -14049,7 +14137,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
add_header(req, "From", from); add_header(req, "From", from);
add_header(req, "To", to); add_header(req, "To", to);
ast_string_field_set(p, exten, l); ast_string_field_set(p, exten, l);
build_contact(p); build_contact(p, req, 0);
add_header(req, "Contact", p->our_contact); add_header(req, "Contact", p->our_contact);
add_header(req, "Call-ID", p->callid); add_header(req, "Call-ID", p->callid);
add_header(req, "CSeq", tmp_n); add_header(req, "CSeq", tmp_n);
@ -14478,7 +14566,6 @@ static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi)
set_socket_transport(&mwi->call->socket, mwi->transport); set_socket_transport(&mwi->call->socket, mwi->transport);
mwi->call->socket.port = htons(mwi->portno); mwi->call->socket.port = htons(mwi->portno);
ast_sip_ouraddrfor(&mwi->call->sa, &mwi->call->ourip, mwi->call); ast_sip_ouraddrfor(&mwi->call->sa, &mwi->call->ourip, mwi->call);
build_contact(mwi->call);
build_via(mwi->call); build_via(mwi->call);
/* Change the dialog callid. */ /* Change the dialog callid. */
@ -15446,7 +15533,6 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
internal network so we can register through nat internal network so we can register through nat
*/ */
ast_sip_ouraddrfor(&p->sa, &p->ourip, p); ast_sip_ouraddrfor(&p->sa, &p->ourip, p);
build_contact(p);
} }
/* set up a timeout */ /* set up a timeout */
@ -15526,6 +15612,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char *
} }
add_expires(&req, r->expiry); add_expires(&req, r->expiry);
build_contact(p, &req, 0);
add_header(&req, "Contact", p->our_contact); add_header(&req, "Contact", p->our_contact);
initialize_initreq(p, &req); initialize_initreq(p, &req);
@ -17055,7 +17142,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
} }
ast_string_field_set(p, exten, name); ast_string_field_set(p, exten, name);
build_contact(p); build_contact(p, req, 1);
if (req->ignore) { if (req->ignore) {
/* Expires is a special case, where we only want to load the peer if this isn't a deregistration attempt */ /* Expires is a special case, where we only want to load the peer if this isn't a deregistration attempt */
const char *expires = sip_get_header(req, "Expires"); const char *expires = sip_get_header(req, "Expires");
@ -18601,8 +18688,9 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
if (t) if (t)
*t = '\0'; *t = '\0';
if (ast_strlen_zero(p->our_contact)) if (ast_strlen_zero(p->our_contact)) {
build_contact(p); build_contact(p, req, 1);
}
} }
of = get_in_brackets(of); of = get_in_brackets(of);
@ -24747,7 +24835,7 @@ static int handle_request_options(struct sip_pvt *p, struct sip_request *req, st
/* must go through authentication before getting here */ /* must go through authentication before getting here */
gotdest = get_destination(p, req, NULL); gotdest = get_destination(p, req, NULL);
build_contact(p); build_contact(p, req, 1);
if (ast_strlen_zero(p->context)) if (ast_strlen_zero(p->context))
ast_string_field_set(p, context, sip_cfg.default_context); ast_string_field_set(p, context, sip_cfg.default_context);
@ -25513,8 +25601,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
goto request_invite_cleanup; goto request_invite_cleanup;
} }
gotdest = get_destination(p, NULL, &cc_recall_core_id); /* Get destination right away */ gotdest = get_destination(p, NULL, &cc_recall_core_id); /* Get destination right away */
extract_uri(p, req); /* Get the Contact URI */ extract_uri(p, req); /* Get the Contact URI */
build_contact(p); /* Build our contact header */ build_contact(p, req, 1); /* Build our contact header */
if (p->rtp) { if (p->rtp) {
ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833); ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
@ -27422,7 +27510,7 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req,
/* Get full contact header - this needs to be used as a request URI in NOTIFY's */ /* Get full contact header - this needs to be used as a request URI in NOTIFY's */
parse_ok_contact(p, req); parse_ok_contact(p, req);
build_contact(p); build_contact(p, req, 1);
/* Initialize tag for new subscriptions */ /* Initialize tag for new subscriptions */
if (ast_strlen_zero(p->tag)) { if (ast_strlen_zero(p->tag)) {

Loading…
Cancel
Save