Discussion:
[SR-Users] kamailio routes packets with invalid From/To headers with uac.restore_mode=auto when incoming packet does not use exact same replaced From/To header
Alex Villací­s Lasso
2014-07-30 21:14:08 UTC
Permalink
I am currently handling a system that runs kamailio and asterisk in the same machine. The kamailio instances are being used to emulate multiple SIP domains, by means of From/To mangling of incoming packets, which are then routed to Asterisk. The attached
kamailio.cfg does this work.

There is an problem when handling SUBSCRIBE requests (as required for BLF and voicemail indications). My configuration is written so that these SUBSCRIBE requests are not handled by kamailio, but instead routed to asterisk. There is a failure to check
From/To headers to see whether NOTIFY packets generated as part of a subscription can be restored using the information in Record-Route. The end result is that kamailio ends up sending packets with garbled tags that are (rightly) rejected by the SIP endpoint.

The following is an example that demonstrates the issue (using Jitsi as endpoint):

After registration, Jitsi sends a SUBSCRIBE request:

SUBSCRIBE sip:avillacisIM-***@public.gmane.org SIP/2.0
Call-ID: ***@0:0:0:0:0:0:0:0
CSeq: 2 SUBSCRIBE
From: "avillacisIM" <sip:avillacisIM-***@public.gmane.org>;tag=bf427f4a
To: "avillacisIM" <sip:avillacisIM-***@public.gmane.org>
Max-Forwards: 70
Contact: "avillacisIM" <sip:avillacisIM-***@public.gmane.org:5060;transport=udp;registering_acc=pbx_villacis_com>
User-Agent: Jitsi2.5.5255Linux
Event: message-summary
Accept: application/simple-message-summary
Expires: 3600
Via: SIP/2.0/UDP 192.168.3.2:5060;branch=z9hG4bK-343638-bd3ea073eb8920481b32962f3221eb6f
Proxy-Authorization: Digest username="avillacisIM",realm="pbx.villacis.com",nonce="U9lZJlPZV/r06Xep/ukc1UzAIO0V3TbS",uri="sip:avillacisIM-***@public.gmane.org",response="0e18f4913c2693f6154c91f158fb17fe"
Content-Length: 0

This packet is mangled by the configuration, and is sent to asterisk like this:

SUBSCRIBE sip:avillacisIM-***@public.gmane.org SIP/2.0
Record-Route: <sip:127.0.0.1;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
Record-Route: <sip:192.168.2.18;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
Call-ID: ***@0:0:0:0:0:0:0:0
CSeq: 2 SUBSCRIBE
From: "avillacisIM" <sip:avillacisIM_pbx.villacis.com-savSHZN5Fh8qMp+***@public.gmane.org:5080>;tag=bf427f4a
To: "avillacisIM" <sip:avillacisIM_pbx.villacis.com-savSHZN5Fh8qMp+***@public.gmane.org:5080>
Max-Forwards: 69
Contact: "avillacisIM" <sip:avillacisIM-***@public.gmane.org:5060;transport=udp;registering_acc=pbx_villacis_com>
User-Agent: Jitsi2.5.5255Linux
Event: message-summary
Accept: application/simple-message-summary
Expires: 3600
Via: SIP/2.0/UDP 127.0.0.1;branch=z9hG4bKd941.2ab9cf36e41dc48855ae2cbe9a309d0a.0
Via: SIP/2.0/UDP 192.168.3.2:5060;rport=5060;branch=z9hG4bK-343638-bd3ea073eb8920481b32962f3221eb6f
Content-Length: 0

The asterisk response for the SUBSCRIBE:

SIP/2.0 200 OK
Via: SIP/2.0/UDP 127.0.0.1;branch=z9hG4bKd941.2ab9cf36e41dc48855ae2cbe9a309d0a.0;received=127.0.0.1;rport=5060
Via: SIP/2.0/UDP 192.168.3.2:5060;rport=5060;branch=z9hG4bK-343638-bd3ea073eb8920481b32962f3221eb6f
Record-Route: <sip:127.0.0.1;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
Record-Route: <sip:192.168.2.18;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
From: "avillacisIM" <sip:avillacisIM_pbx.villacis.com-savSHZN5Fh8qMp+***@public.gmane.org:5080>;tag=bf427f4a
To: "avillacisIM" <sip:avillacisIM_pbx.villacis.com-savSHZN5Fh8qMp+***@public.gmane.org:5080>;tag=as5562e95e
Call-ID: ***@0:0:0:0:0:0:0:0
CSeq: 2 SUBSCRIBE
Server: Asterisk PBX 11.11.0
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
Expires: 3600
Contact: <sip:avillacisIM-savSHZN5Fh8qMp+***@public.gmane.org:5080>;expires=3600
Content-Length: 0

This is in turn transformed back by kamailio, and sent to Jitsi like this:

SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.3.2:5060;rport=5060;branch=z9hG4bK-343638-bd3ea073eb8920481b32962f3221eb6f
Record-Route: <sip:127.0.0.1;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
Record-Route: <sip:192.168.2.18;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
From: "avillacisIM" <sip:avillacisIM-***@public.gmane.org>;tag=bf427f4a
To: "avillacisIM" <sip:avillacisIM-***@public.gmane.org>;tag=as5562e95e
Call-ID: ***@0:0:0:0:0:0:0:0
CSeq: 2 SUBSCRIBE
Server: Asterisk PBX 11.11.0
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
Expires: 3600
Contact: <sip:avillacisIM-savSHZN5Fh8qMp+***@public.gmane.org:5080;alias=127.0.0.1~5080~1>;expires=3600
Content-Length: 0

Now asterisk wants to send a NOTIFY to the endpoint for the subscription. The NOTIFY looks like this:

NOTIFY sip:avillacisIM-***@public.gmane.org:5060;transport=udp;registering_acc=pbx_villacis_com SIP/2.0
Via: SIP/2.0/UDP 127.0.0.1:5080;branch=z9hG4bK658fa5fc;rport
Max-Forwards: 70
Route:
<sip:127.0.0.1;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>,<sip:192.168.2.18;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
From: "asterisk" <sip:asterisk-savSHZN5Fh8qMp+***@public.gmane.org:5080>;tag=as5562e95e
To: <sip:avillacisIM-***@public.gmane.org:5060;transport=udp;registering_acc=pbx_villacis_com>;tag=bf427f4a
Contact: <sip:asterisk-savSHZN5Fh8qMp+***@public.gmane.org:5080>
Call-ID: ***@0:0:0:0:0:0:0:0
CSeq: 102 NOTIFY
User-Agent: Asterisk PBX 11.11.0
Event: message-summary
Content-Type: application/simple-message-summary
Subscription-State: active
Content-Length: 89

Messages-Waiting: no
Message-Account: sip:*97-savSHZN5Fh8qMp+***@public.gmane.org:5080
Voice-Message: 0/0 (0/0)

Here is where the bug appears. The autoprocessing does not recognize that the From header (From: "asterisk" <sip:asterisk-savSHZN5Fh8qMp+***@public.gmane.org:5080>;tag=as5562e95e) from the above request has nothing to do with the saved information (vsf parameter). Instead, it
blindly mangles the From header, and does not even run a sanity check on the result before routing it. The end result is shown below.

NOTIFY sip:avillacisIM-***@public.gmane.org:5060;transport=udp;registering_acc=pbx_villacis_com SIP/2.0
Record-Route: <sip:192.168.2.18;r2=on;lr=on;ftag=as5562e95e>
Record-Route: <sip:127.0.0.1;r2=on;lr=on;ftag=as5562e95e>
Via: SIP/2.0/UDP 192.168.2.18;branch=z9hG4bK8333.8bfe7bc2bd554a8631f0d00d463b28ee.0
Via: SIP/2.0/UDP 127.0.0.1:5080;branch=z9hG4bK658fa5fc;rport=5080
Max-Forwards: 69
From: "asterisk" <sip:***@12(.0.0.1:5080.....-savSHZN5Fh8qMp+***@public.gmane.org:5080>;tag=as5562e95e
To: <sip:avillacisIM-***@public.gmane.org:5060;transport=udp;registering_acc=pbx_villacis_com>;tag=bf427f4a
Contact: <sip:asterisk-savSHZN5Fh8qMp+***@public.gmane.org:5080>
Call-ID: ***@0:0:0:0:0:0:0:0
CSeq: 102 NOTIFY
User-Agent: Asterisk PBX 11.11.0
Event: message-summary
Content-Type: application/simple-message-summary
Subscription-State: active
Content-Length: 89

Messages-Waiting: no
Message-Account: sip:*97-savSHZN5Fh8qMp+***@public.gmane.org:5080
Voice-Message: 0/0 (0/0)

From examination of the source code, the vsf and vst strings are base64 encodings of the result of XORing the byte strings of the old and new tags. For this to work, the headers of future packets should match. However, here kamailio does not realize that
the header does not match (by the ftag), and also does not check that the resulting "restored" header is a valid header.
Daniel-Constantin Mierla
2014-08-01 06:24:12 UTC
Permalink
The uac from/to replacement relies that parties keep the same from/to
headers content.

The mechanism to replace A with B is to combine both and get the key X
which is added in the record-route as parameter. Then practically from A
and X results B and from B and X results A.

Now in this case, the notify comes with something different than was in
SUBSCRIBE, therefore the result is messed up.

Perhaps a check over the result to see if it is at least a good value
would be useful, but doesn't solve this issue.

If both sides in this dialog rely on RFC3261 dialog matching (call-id,
from tag and to tag), then practically after the initial SUBSCRIBE
(where is no To tag), then you can replace From/To display name and uri
with anything (e.g., anonymous).

An improvement could be to know in advance that one side is not keeping
From/To, then practically storing (encrypted/encode) the intial value
only. This requires C coding.

Cheers,
Daniel
Post by Alex Villací­s Lasso
I am currently handling a system that runs kamailio and asterisk in
the same machine. The kamailio instances are being used to emulate
multiple SIP domains, by means of From/To mangling of incoming
packets, which are then routed to Asterisk. The attached kamailio.cfg
does this work.
There is an problem when handling SUBSCRIBE requests (as required for
BLF and voicemail indications). My configuration is written so that
these SUBSCRIBE requests are not handled by kamailio, but instead
routed to asterisk. There is a failure to check From/To headers to see
whether NOTIFY packets generated as part of a subscription can be
restored using the information in Record-Route. The end result is that
kamailio ends up sending packets with garbled tags that are (rightly)
rejected by the SIP endpoint.
The following is an example that demonstrates the issue (using Jitsi
CSeq: 2 SUBSCRIBE
Max-Forwards: 70
Contact: "avillacisIM"
User-Agent: Jitsi2.5.5255Linux
Event: message-summary
Accept: application/simple-message-summary
Expires: 3600
Via: SIP/2.0/UDP
192.168.3.2:5060;branch=z9hG4bK-343638-bd3ea073eb8920481b32962f3221eb6f
Proxy-Authorization: Digest
Content-Length: 0
This packet is mangled by the configuration, and is sent to asterisk
<sip:127.0.0.1;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
<sip:192.168.2.18;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
CSeq: 2 SUBSCRIBE
From: "avillacisIM"
Max-Forwards: 69
Contact: "avillacisIM"
User-Agent: Jitsi2.5.5255Linux
Event: message-summary
Accept: application/simple-message-summary
Expires: 3600
Via: SIP/2.0/UDP
127.0.0.1;branch=z9hG4bKd941.2ab9cf36e41dc48855ae2cbe9a309d0a.0
Via: SIP/2.0/UDP
192.168.3.2:5060;rport=5060;branch=z9hG4bK-343638-bd3ea073eb8920481b32962f3221eb6f
Content-Length: 0
SIP/2.0 200 OK
Via: SIP/2.0/UDP
127.0.0.1;branch=z9hG4bKd941.2ab9cf36e41dc48855ae2cbe9a309d0a.0;received=127.0.0.1;rport=5060
Via: SIP/2.0/UDP
192.168.3.2:5060;rport=5060;branch=z9hG4bK-343638-bd3ea073eb8920481b32962f3221eb6f
<sip:127.0.0.1;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
<sip:192.168.2.18;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
From: "avillacisIM"
To: "avillacisIM"
CSeq: 2 SUBSCRIBE
Server: Asterisk PBX 11.11.0
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY,
INFO, PUBLISH, MESSAGE
Supported: replaces, timer
Expires: 3600
Content-Length: 0
This is in turn transformed back by kamailio, and sent to Jitsi like
SIP/2.0 200 OK
Via: SIP/2.0/UDP
192.168.3.2:5060;rport=5060;branch=z9hG4bK-343638-bd3ea073eb8920481b32962f3221eb6f
<sip:127.0.0.1;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
<sip:192.168.2.18;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
CSeq: 2 SUBSCRIBE
Server: Asterisk PBX 11.11.0
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY,
INFO, PUBLISH, MESSAGE
Supported: replaces, timer
Expires: 3600
Content-Length: 0
Now asterisk wants to send a NOTIFY to the endpoint for the
NOTIFY
SIP/2.0
Via: SIP/2.0/UDP 127.0.0.1:5080;branch=z9hG4bK658fa5fc;rport
Max-Forwards: 70
<sip:127.0.0.1;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>,<sip:192.168.2.18;r2=on;lr=on;ftag=bf427f4a;vsf=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;vst=AAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAABAMTI3LjAuMC4xOjUwODA-;nat=yes>
CSeq: 102 NOTIFY
User-Agent: Asterisk PBX 11.11.0
Event: message-summary
Content-Type: application/simple-message-summary
Subscription-State: active
Content-Length: 89
Messages-Waiting: no
Voice-Message: 0/0 (0/0)
Here is where the bug appears. The autoprocessing does not recognize
that the From header (From: "asterisk"
has nothing to do with the saved information (vsf parameter). Instead,
it blindly mangles the From header, and does not even run a sanity
check on the result before routing it. The end result is shown below.
NOTIFY
SIP/2.0
Record-Route: <sip:192.168.2.18;r2=on;lr=on;ftag=as5562e95e>
Record-Route: <sip:127.0.0.1;r2=on;lr=on;ftag=as5562e95e>
Via: SIP/2.0/UDP
192.168.2.18;branch=z9hG4bK8333.8bfe7bc2bd554a8631f0d00d463b28ee.0
Via: SIP/2.0/UDP 127.0.0.1:5080;branch=z9hG4bK658fa5fc;rport=5080
Max-Forwards: 69
From: "asterisk"
CSeq: 102 NOTIFY
User-Agent: Asterisk PBX 11.11.0
Event: message-summary
Content-Type: application/simple-message-summary
Subscription-State: active
Content-Length: 89
Messages-Waiting: no
Voice-Message: 0/0 (0/0)
From examination of the source code, the vsf and vst strings are
base64 encodings of the result of XORing the byte strings of the old
and new tags. For this to work, the headers of future packets should
match. However, here kamailio does not realize that the header does
not match (by the ftag), and also does not check that the resulting
"restored" header is a valid header.
_______________________________________________
SIP Express Router (SER) and Kamailio (OpenSER) - sr-users mailing list
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
--
Daniel-Constantin Mierla - http://www.asipto.com
http://twitter.com/#!/miconda - http://www.linkedin.com/in/miconda
Alex Villací­s Lasso
2014-08-01 22:03:35 UTC
Permalink
The uac from/to replacement relies that parties keep the same from/to headers content.
The mechanism to replace A with B is to combine both and get the key X which is added in the record-route as parameter. Then practically from A and X results B and from B and X results A.
Now in this case, the notify comes with something different than was in SUBSCRIBE, therefore the result is messed up.
Perhaps a check over the result to see if it is at least a good value would be useful, but doesn't solve this issue.
If both sides in this dialog rely on RFC3261 dialog matching (call-id, from tag and to tag), then practically after the initial SUBSCRIBE (where is no To tag), then you can replace From/To display name and uri with anything (e.g., anonymous).
An improvement could be to know in advance that one side is not keeping From/To, then practically storing (encrypted/encode) the intial value only. This requires C coding.
I had to patch kamailio to work around the issue. What I did is to calculate a small (8-bit) XOR checksum of the old uri, and prepend this byte on the old uri in order to calculate the rr parameter. On restoring, the value should match, and if it does not,
the relevant header is left unchanged.

Is this strategy worthy of submitting for merge, or is it too hacky?
Loading...