[Home]

Summary:ASTERISK-23267: Expires In Contact Header Of 200 OK From Outbound Registration Response Is Ignored Due To Contact URI Parameters Being Added
Reporter:Adam Dugan (dugana)Labels:
Date Opened:2014-02-10 06:53:21.000-0600Date Closed:
Priority:MinorRegression?
Status:Open/NewComponents:Channels/chan_sip/General Channels/chan_sip/Interoperability
Versions:SVN 1.8.20.1 1.8.25.0 11.7.0 12.0.0 13.18.4 Frequency of
Occurrence
Constant
Related
Issues:
Environment:AstLinux 1.1.0Attachments:
Description:When Asterisk receives Contact header expires parameter it will update the expiry for the registration only if it exactly matches the contact used in the registration request.

Asterisk sends register request with:
{noformat}
REGISTER
From: <sip:2125551000@192.168.1.1:5060>;tag=xxxxxxxxxx
{noformat}

This 200 OK will cause Asterisk to update expiration to 125 seconds.
{noformat}
200 OK
Contact: <sip:2125551000@192.168.1.1:5060>;expires=125
{noformat}

This 200 OK will cause Asterisk to ignore the contact header and use it's default expiry instead of the one specified:
{noformat}
Contact: <sip:2125551000@192.168.1.1:5060;ep=192.168.1.1;fw=74.125.235.232>;expires=125
{noformat}


This issue has been discussed before and closed, but in the previous instance the URI in the contact header was not formatted correctly (see: ASTERISK-14870 ).

Per the RFC:
{quote}
RFC 3261 10.3 Processing REGISTER Requests

     8. The registrar returns a 200 (OK) response.  The response MUST
        contain Contact header field values enumerating all current
        bindings.  Each Contact value MUST feature an "expires"
        parameter indicating its expiration interval chosen by the
        registrar. The response SHOULD include a Date header field.

RFC 3261 19.1.4 URI Comparison

URI uri-parameter components are compared as follows:

        -  Any uri-parameter appearing in both URIs must match.

        -  A user, ttl, or method uri-parameter appearing in only one
           URI never matches, even if it contains the default value.

        -  A URI that includes an maddr parameter will not match a URI
           that contains no maddr parameter.

        -  All other uri-parameters appearing in only one URI are
           ignored when comparing the URIs.
{quote}

I've been pouring over the RFC trying to figure out what is correct. Sections I've read could interpret to mean the Contact header returned in the 200 OK must exactly match that used in the register request, and that the URI parameters might be ok.

I'm currently using a VoIP provider that is returning a Contact header in the 200 OK with endpoint and firewall (ep & fw) URI parameters. This is causing Asterisk not to respect the expires time and subsequently causing my registration to timeout on the carrier side before Asterisk re-registers. As the carrier requests an expiry less then the minimum allowed upon connect there is no way to successfully stay connected editing the Asterisk configuration files alone.

The Oracle Session Border Controller seems to have the behavior of adding the fw firewall and ep endpoint URI parameters to the Contact field of SIP packets. See Using Private IPv4 Addresses, Page 282: http://docs.oracle.com/cd/E50377_01/doc/sbc_sc610_acliconfiguration.pdf

Looking at the code it does appear there is a string compare. I haven't traced back to the parse yet to see if it's stripping out the URI parameters. Based on the behavior I've experienced it isn't.  

http://svnview.digium.com/svn/asterisk/branches/1.8/channels/chan_sip.c?revision=406170&view=markup
{code}
21558 if (!ast_strlen_zero(get_header(req, "Contact"))) {
21559 const char *contact = NULL;
21560 const char *tmptmp = NULL;
21561 int start = 0;
21562 for(;;) {
21563 contact = __get_header(req, "Contact", &start);
21564 /* this loop ensures we get a contact header about our register request */
21565 if(!ast_strlen_zero(contact)) {
21566 if( (tmptmp=strstr(contact, p->our_contact))) {
21567 contact=tmptmp;
21568 break;
21569 }
21570 } else
21571 break;
21572 }
21573 tmptmp = strcasestr(contact, "expires=");
21574 if (tmptmp) {
21575 if (sscanf(tmptmp + 8, "%30d", &expires) != 1) {
21576 expires = 0;
21577 }
21578 }
21579
21580 }
21581 if (!expires)
21582 expires=atoi(get_header(req, "expires"));
21583 if (!expires)
21584 expires=default_expiry;
{code}

With debugging on:
{noformat}
REGISTER:
[2014-02-07 21:45:18] DEBUG[1663]: chan_sip.c:8914 parse_request:  Header 10 [ 40]: Contact: <sip:2125551000@191.168.1.1:5060>

200 OK:
[2014-02-07 21:45:18] DEBUG[1663]: chan_sip.c:8914 parse_request:  Header  6 [ 80]: Contact: <sip:2125551000@192.168.1.1:5060;ep=192.168.1.1;fw=74.125.235.232>;expires=155
{noformat}


I've tried to find someone in the forums & IRC channels to provide opinions on whether Asterisk or Oracle is following the standard and which one isn't. As Asterisk is intended to be interoperable with other SIP products, and Oracle is a major manufacturer there probably should be a solution.


Comments:By: Michael L. Young (elguero) 2014-02-10 10:21:35.276-0600

Can you try a newer version of Asterisk (1.8.25)?

There have been a couple of issues fixed around the Expires header.  ASTERISK-22574 seems to match the sample you have in the description.  There is no semicolon on the end of "expires" in what you posted above.

_*Edited:*_
Although, I just re-read your description and see that you say if the URI is identical, you don't have this issue.  Probably wouldn't hurt to try an updated version anyways since there was another issue fixed in regards to handling of the Expires header.

Please attach copy of your full debug logs as well, since that might be helpful when digging into this issue if updating doesn't fix it.

By: Michael L. Young (elguero) 2014-02-10 11:00:26.806-0600

Ok.  So after posting my comment above, I dug around in the code a bit and I can confirm / see what you described above.

We are doing a sub-string comparison but the new incoming Contact header contains more characters than the original Contact header did and therefore no match is made when making the comparison.

I think the last bullet item in the list for URI comparison may be missing here.  We are not parsing out the extra parameters that are in the 200 OK before comparing.

Perhaps someone else can chime in to confirm that this conclusion is correct.

By: Adam Dugan (dugana) 2014-02-12 11:39:01.926-0600

Fresh install of Debian 7.4.0 i386 & Asterisk 1.8.25 compiled from source.

It seems with an expires=250 (shown below) or expires=190 (not shown) returned in the contact header Asterisk is parsing it as 120 and scheduling in 105.

REGISTER:
{noformat}
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  0 [ 39]: REGISTER sip:sip.provider.net SIP/2.0
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  1 [ 62]: Via: SIP/2.0/UDP 192.168.1.1:5060;branch=UHGNqF5g9xD2XRB;rport
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  2 [ 16]: Max-Forwards: 70
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  3 [ 56]: From: <sip:2125551000@sip.provider.net>;tag=xd56e9cf77
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  4 [ 39]: To: <sip:2125551000@sip.provider.net>
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  5 [ 51]: Call-ID: baQEzBAsfKNAhBrJSbH8APbTEnrVZMmx@127.0.1.1
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  6 [ 18]: CSeq: 108 REGISTER
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  7 [ 33]: User-Agent: Asterisk PBX 1.8.25.0
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  8 [225]: Authorization: Digest username="2125551000", realm="sip.provider.net", algorithm=MD5, uri="sip:sip.provider.net", nonce="6s3wAWLmXG6Z", response="rqcRcKzvVERd9yfgZjrgYk8EYm4tdFZV", qop=auth, cnonce="671de2386", nc=00000000
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  9 [ 13]: Expires: 3600
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header 10 [ 42]: Contact: <sip:2125551000@192.168.1.1:5060>
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header 11 [ 17]: Content-Length: 0
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header 12 [  0]:
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:4143 __sip_reliable_xmit: *** SIP TIMER: Initializing retransmit timer on packet: Id  #30
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:3688 __sip_xmit: Trying to put 'REGISTER si' onto UDP socket destined for 74.125.235.232:5060
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:3318 registry_unref: SIP Registry sip.provider.net: refcount now 3
{noformat}

200 OK:
{noformat}
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  0 [ 14]: SIP/2.0 200 OK
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  1 [ 95]: Via: SIP/2.0/UDP 192.168.1.1:5060;received=74.125.235.232;branch= EY5M7xgLFfM4Jg4;rport=57802;alias
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  2 [ 56]: From: <sip:2125551000@sip.provider.net>;tag=xd56e9cf77
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  3 [ 69]: To: <sip:2125551000@sip.provider.net>;tag= rN9EKnbF9hQbFCFHrestdBhk6
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  4 [ 51]: Call-ID: baQEzBAsfKNAhBrJSbH8APbTEnrVZMmx@127.0.1.1
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  5 [ 18]: CSeq: 108 REGISTER
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8962 parse_request:  Header  6 [ 84]: Contact: <sip:2125551000@192.168.1.1:5060;ep=192.168.1.1;fw=74.125.235.232>;expires=250
--- (8 headers 0 lines) ---
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:8553 find_call: = Looking for  Call ID: baQEzBAsfKNAhBrJSbH8APbTEnrVZMmx@127.0.1.1 (Checking To) --From tag xd56e9cf77 --To-tag rN9EKnbF9hQbFCFHrestdBhk6
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:4339 __sip_ack: ** SIP TIMER: Cancelling retransmit of packet (reply received) Retransid #30
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:4372 __sip_ack: Stopping retransmission on 'baQEzBAsfKNAhBrJSbH8APbTEnrVZMmx@127.0.1.1' of Request 108: Match Found
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:21495 handle_response_register: Registration successful
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:21497 handle_response_register: Cancelling timeout 29
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:3318 registry_unref: SIP Registry sip.provider.net: refcount now 1
Scheduling destruction of SIP dialog 'baQEzBAsfKNAhBrJSbH8APbTEnrVZMmx@127.0.1.1' in 32000 ms (Method: REGISTER)
[Feb 10 18:55:35] NOTICE[22982]: chan_sip.c:21548 handle_response_register: Outbound Registration: Expiry for sip.provider.net is 120 sec (Scheduling reregistration in 105 s)
[Feb 10 18:55:35] DEBUG[22982]: chan_sip.c:3326 registry_addref: SIP Registry sip.provider.net: refcount now 1
[Feb 10 18:56:07] DEBUG[22982]: chan_sip.c:4228 __sip_autodestruct: Auto destroying SIP dialog 'baQEzBAsfKNAhBrJSbH8APbTEnrVZMmx@127.0.1.1'
[Feb 10 18:56:07] DEBUG[22982]: chan_sip.c:6449 sip_destroy: Destroying SIP dialog baQEzBAsfKNAhBrJSbH8APbTEnrVZMmx@127.0.1.1
Really destroying SIP dialog 'baQEzBAsfKNAhBrJSbH8APbTEnrVZMmx@127.0.1.1' Method: REGISTER
[Feb 10 18:56:07] DEBUG[22982]: chan_sip.c:19450 sip_dump_history:
---------- SIP HISTORY for 'baQEzBAsfKNAhBrJSbH8APbTEnrVZMmx@127.0.1.1'
{noformat}

By: Michael L. Young (elguero) 2014-02-12 13:24:39.974-0600

Okay, I think I am understanding what is happening better.  I apologize for not understanding the issue from the beginning and thank you for the sip debug which helped me understand better the issue being described.

So, basically the problem here is strictly that the expires header is not being found and therefore the default value is being used.  I do see what the issue is and I can come up with a patch for you.  The problem does have to do with what I described in an earlier comment.  This isn't necessarily a RFC interpretation issue, which is what I was thinking it was.

By: Adam Dugan (dugana) 2014-02-12 13:34:47.841-0600

In the previous example post the default expire was 3600 as seen in the REGISTER request? The 200 OK response amends the expire value to 250 in that example but I'm not sure where Asterisk is getting 120 from?

As far as the RFC: Should the contact header exactly match the one supplied in the register request? Or, is it legal for the UAS to add URI parameters to the contact header when returning a 200 OK?

In either case, Asterisk should probably strip URI parameters when matching the Contact header for compatibility to ensure it respects an updated expire time per 3261 10.3 (8).

By: Michael L. Young (elguero) 2014-02-12 13:39:07.097-0600

When processing the response, it looks for the "expires" in the Contact header.  If one is not found, which it is not finding based on the current method for trying to match the contact uri, it then looks for an Expires header, which is not present.  With the Expires header missing and with Asterisk not finding it in the Contact header, the code then uses the built in default value which is 120.

By: Rusty Newton (rnewton) 2014-02-18 18:22:04.344-0600

Keeping this as assigned to Michael since he mentioned he is working on a patch. Thanks Michael!