Wednesday, August 21, 2013

RTPproxy Revisited [Kamailio 4.0]

Time and again I see people getting stuck on RTPproxy integration with Kamailio. I recently got another opportunity to put RTPproxy in between the User Phones and Kamailio setup as depicted in the following diagram.



That is similar to what I've posted earlier on this topic. In this post I will try be more verbose and write each and every step I did to have RTPs flowing.

I assume you've a Kamailio installed and working and configurations file from Asipto Knowledge Base by Daniel and that there are TWO NICs configured with Public IP and Private IP as shown in the diagram above.

The important thing which I'm looking for from the configuration is the WITH_NAT tag. follow the code and see how the NAT is handled. route[NATMANAGE] is called at almost all important routes.

The overall idea is;

1- Install RTPproxy
2- Start RTPproxy in Bridged mode
3- Make Kamailio aware of multiple NICs
4- Add Private IP asterisks in dispatcher
5- Create a new route RTPPROXY to engage RTP-proxy whenever needed
6- Call in the RTPPROXY route in the NATMANAGE route.
7- Important Things to take care of.

So lets start following the steps.

1- Installing RTPproxy

root@Kamailio:~# cd /usr/src/
root@Kamailio:~# wget http://b2bua.org/chrome/site/rtpproxy-1.2.1.tar.gz
root@Kamailio:~# tar zxvf rtpproxy-1.2.1.tar.gz
root@Kamailio:~# cd rtpproxy-1.2.1/
root@Kamailio:~# ./configure
root@Kamailio:~# make
root@Kamailio:~# make install

Setup LSB script for RTP-proxy
root@Kamailio:~# cp debian/rtpproxy-default.ex /etc/default/rtpproxy
edit the default file and put in the parameters.
root@Kamailio:~# vim /etc/default/rtpproxy

2- Start RTPproxy in Bridged mode


DAEMON_OPTS="-F -s udp:127.0.0.1:7722 -l 77.66.55.44/192.168.1.244 -d DBUG:LOG_LOCAL0 -u root"

Save and Exit

root@Kamailio:~# cp debian/rtpproxy.init /etc/init.d/rtpproxy
root@Kamailio:~# chmod a+x /etc/init.d/rtpproxy

Open up the file

root@Kamailio:~# vim /etc/init.d/rtpproxy

see that the DAEMON field points to the file in /usr/bin/rtpproxy

DAEMON=/usr/bin/rtpproxy

Lets copy the RTPproxy binary to that location.

root@Kamailio:~# cp rtpproxy /usr/bin/rtpproxy

Start up RTPproxy

root@Kamailio:~# /etc/init.d/rtpproxy start

verify that rtpproxy is running and listening on the specified 7722 

root@Kamailio:~# netstat -pln | grep rtpp
udp        0      0 127.0.0.1:7722          0.0.0.0:*                           6554/rtpproxy
Thats all.

3- Making Kamailio aware of multiple NICs


Lets move on to step 3 involving Kamailio configurations.

root@Kamailio:~# vim /usr/local/etc/kamailio/kamailio.cfg

Insert the following line in global parameters section, just under where we define "listen=" or "port=" 

mhomed=1

That will ensure that Kamailio uses its Private IP to communicate with Asterisks on Private subnet. Don't forget this.

We also need to put this line on the top definitions of kamailio.cfg file so kamailio use the NAT functions.

#!define WITH_NAT

4- Adding Asterisks to dispatcher


Now Add Private IP asterisks in dispatcher: Follow my post on adding dispatcher to the plain configurations from here: http://saevolgo.blogspot.com/2011/11/how-to-increasing-voip-services.html

5- Writing some Kamailio routing logic for RTPPROXY

That was easy, now the real thing the addition of RTPPROXY route which I modified a little bit from the last link mentioned.

To have the code working I have used the SQLOPS module configured to query kamailio.dispatcher table as the AVPOPS module was already busy.

NOTE: Using the DB query is a costly operation BUT it allows me to detect if Kamailio is sending call to Dispatcher listed IPs or not. I have a mix of Asterisks on Private Subnet and on Public Subnet and if the Asterisk dispatcher has chosen or the call is coming from is a Private IP then engage RTPproxy. This detection is handled by IPOPS module and its function is_ip_rfc1918()

loadmodule "ipops.so"
loadmodule "sqlops.so"
modparam("sqlops","sqlcon","ca=>mysql://openser:openserrw@localhost/kamailio")

Then declare the route:

# RTPProxy control
route[RTPPROXY] {
        if (is_method("INVITE")){
                sql_query("ca", "select destination from dispatcher where destination like '%$dd%'","ra");
                if($dbr(ra=>rows)>0){
                        $avp(duip)=$(du{s.select,-2,:});
                        if (is_ip_rfc1918("$avp(duip)")) {
                                xlog("L_INFO", "Call is going to private IPv4 Media Server Engage RTPProxy Now\n");
                                #rtpproxy_manage("crwie","192.168.1.244");
                                rtpproxy_manage("rwie");
                        }

                }
                else if(ds_is_from_list()){
                        if (is_ip_rfc1918("$si")) {
                                xlog("L_INFO", " Call is coming from a private IPv4 Media Server Engage RTPProxy Now\n");
                                #rtpproxy_manage("crwei","77.66.55.44");
                                rtpproxy_manage("rwei");

                        }
                }else if(!ds_is_from_list()){
                          rtpproxy_manage("rwie");

                }
      }
}

6- Using RTPPROXY route

Add the RTPPROXY route just where the FLT_NATS and FLB_NATB flags are tested.

        if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB))){
                return;
        }
                route(RTPPROXY);


Now Save and Exit the kamailio.cfg file.

Restart Kamailio.

root@Kamailio:~# /etc/init.d/kamailio stop
root@Kamailio:~# /etc/init.d/kamailio start

7- Helpful Things to know

Asterisk needs to have the peer declared for kamailio using its Private IP.

[Kamailio]
type=friend
host=192.168.1.244
port=5060
disallow=all
allow=gsm
allow=g729
allow=alaw
allow=ulaw
context=SBC-Incoming
canreinvite=no
insecure=port,invite
nat=force_rport,comedia
qualify=yes
directrtpsetup=no

See that I've used "directrtpsetup=no" so that Asterisk don't decide to go direct with the End caller.

Use xlog lines in kamailio.cfg file to follow the call.

The way I always setup my whole environment is that Kamailio handles the REGISTRATIONs and only INVITES are load-balanced to Asterisks or FreeSWITCHes where they receive the call from Kamailio peer and execute dialplan applications and IF call needs to dial out they dial the destination back to kamailio.
Kamailio needs to detect the call coming FROM the Media-Servers (ds_is_from_list() function)

So I know when a user calls in and when the call comes in from the media-servers.

Always try to first have an echo test working for calls. I use Asterisk application Echo() and when I dial in from user I get my own audio echoed back and I know that atleast my audio path is complete. This never tells you that your setup is 100% perfect but it is a good way to know if you're headed right direction.


Wireshark is a great Friend. Use it to examine everything in depth. No matter what I do I always need Wireshark to visually see what is going on with the SIP packets, that gives me everything I need to know to make things right.

root@Kamailio200:~# tcpdump -i any -s 0 -w rtp-calls.pcap -vvv
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
1666 packets captured
Download this "rtp-calls.pcap" file and open it up in Wireshark. Click "Telephony"  from the menu bar and select "VoIP Calls"


Hit the Flow button and you'll see beautiful arrows showing the direction of SIP and RTP packets.


On the very Left Hand side is my Soft Phone's Public IP address, then 77.66.55.44 is kamailio's WAN side, and suddenly we see 192.168.1.244 which is Private IP of Kamailio communicating with an Asterisk on 192.168.1.36
The Bold arrows labeled RTP are flowing in both direction means all Perfect.

Thats all for one day. Hope to have some comments and questions on this soon.

29 comments:

  1. Thank you very much!

    How to configure kamailio+rtp to work on multiply interfaces ?
    eth0 - LAN
    eth1 - VLAN1
    eth1 - VLAN2
    eth2 - WAN

    ReplyDelete
    Replies
    1. An excellent question, although it requires an extra blog post but I'll try explain the concept.

      1- Identify your NICs to be bridged. Just need to know a logical view which interface for rtpproxy to be used in what case?

      2- Start multiple daemons of RTpproxy with different listeners ports and differnt VLANs used.

      3- In kamailio.cfg connect with multiple RTPproxy instances like this:
      # multiple sets of multiple rtproxies
      modparam("rtpproxy", "rtpproxy_sock",
      "1 == udp:localhost:12221")
      modparam("rtpproxy", "rtpproxy_sock",
      "2 == udp:localhost:12225")

      and then from the SIP traffic identifiy which set of RTPproxy to engage by this function: set_rtp_proxy_set("2");

      That is a very very brief summary.

      Delete
  2. Hello!

    i have error in route[TOASTERISK] section
    in line
    > ds_mark_dst("P");

    > ERROR: [usr_avp.c:437]: search_avp(): ERROR:avp:search_first_avp: 0 ID or NULL NAME AVP!

    and sip debug in asterisk
    <--- SIP read from UDP:192.168.30.250:6000 --->
    INVITE sip:110@PU.BL.IC.IP:6000;transport=UDP SIP/2.0
    Record-Route:
    Record-Route:
    Via: SIP/2.0/UDP 192.168.30.250:6000;branch=z9hG4bK49cf.52e49675.0
    Via: SIP/2.0/UDP CL.IE.NT.IP:37176;branch=z9hG4bK-d8754z-3c51331a1cd05eae-1---d8754z-;rport=37176
    Max-Forwards: 16
    Contact:
    To:
    From: ;tag=832a5f3f
    Call-ID: ZGFhZDFmZGY5ZDU0ODkzYzQ2NzY0ZjliMzYzZThiNWE.
    CSeq: 2 INVITE
    Allow: INVITE, ACK, CANCEL, BYE, NOTIFY, REFER, MESSAGE, OPTIONS, INFO, SUBSCRIBE
    Content-Type: application/sdp
    Supported: replaces, norefersub, extended-refer, timer, X-cisco-serviceuri
    User-Agent: Zoiper r19016
    Allow-Events: presence, kpml
    Content-Length: 309

    v=0
    o=Z 0 0 IN IP4 PU.BL.IC.IPPU.BL.IC.IP
    s=Z
    c=IN IP4 PU.BL.IC.IPPU.BL.IC.IP
    t=0 0
    m=audio 1227412274 RTP/AVP 3 110 98 8 0 101
    a=rtpmap:110 speex/8000
    a=rtpmap:98 iLBC/8000
    a=fmtp:98 mode=20
    a=rtpmap:101 telephone-event/8000
    a=fmtp:101 0-15
    a=sendrecv
    a=nortpproxy:yes
    a=nortpproxy:yes

    with error
    [Aug 31 02:17:56] ERROR[17594]: netsock2.c:269 ast_sockaddr_resolve: getaddrinfo("PU.BL.IC.IPPU.BL.IC.IP", "(null)", ...): No address associated with hostname
    [Aug 31 02:17:56] WARNING[17594]: chan_sip.c:9973 process_sdp_c: Unable to lookup RTP Audio host in c= line, 'IN IP4 PU.BL.IC.IPPU.BL.IC.IP'

    ReplyDelete
    Replies
    1. As for the AVP error check ur avp configuation as follows....
      modparam("dispatcher", "dst_avp", "$avp(i:271)")
      modparam("dispatcher", "grp_avp", "$avp(i:272)")
      modparam("dispatcher", "cnt_avp", "$avp(i:273)")

      Delete
  3. in route[NATMANAGE]
    when i register and call from 10.10.101.50 (private ISP.LAN)
    nat_uac_test("19") return true
    and i have correct INVITE (192.168.30.250 is my kamailio&rtpproxy lan side)
    v=0
    o=Z 0 0 IN IP4 192.168.30.250
    s=Z
    c=IN IP4 192.168.30.250
    t=0 0
    m=audio 17530 RTP/AVP 3 110 98 8 0 101
    a=rtpmap:110 speex/8000
    a=rtpmap:98 iLBC/8000
    a=fmtp:98 mode=20
    a=rtpmap:101 telephone-event/8000
    a=fmtp:101 0-15
    a=sendrecv
    a=nortpproxy:yes

    but when i switch to GSM connection
    nat_uac_test("19") return FALSE
    and i have invalid INVITE (10.133.19.49 is IP behind GSM NAT)
    v=0
    o=Z 0 0 IN IP4 10.133.19.49
    s=Z
    c=IN IP4 10.133.19.49
    t=0 0
    m=audio 57756 RTP/AVP 3 110 98 8 0 101
    a=rtpmap:110 speex/8000
    a=rtpmap:98 iLBC/8000
    a=fmtp:98 mode=20
    a=rtpmap:101 telephone-event/8000
    a=fmtp:101 0-15
    a=sendrecv

    ReplyDelete
    Replies
    1. Read this:
      http://www.kamailio.org/docs/modules/4.0.x/modules/nathelper.html#idp15376536
      This is really tough then...hmmm...Your "Public IP" is again a Private IP. !!?

      Delete
    2. no. 10.133.19.49 is GSM private IP ! 192.168.30.250 is kamailio lan ip

      Delete
    3. Like I said read the link and put the right value in the nat_test function, could be like (31) or so. I suggest take a full packet trace to know from which IP this GSM SIP traffic is coming, is it Public? or Private ?
      Also post the situation on User mailing list to get a more accurate solution.

      Delete
  4. Hi Ahmed,
    first- thank you for this excellent blog. I am starting to learn about kamailio (I am asterisk admin) and I have one question. Is it "correct" to use kamailio with sip peers and asterisk which are all in private lan (no UA coming from wan side). Kamailio would have one interface point to provider, also with private IP address from provider, and one interface in subnet together with couple of asterisk servers and sip peers. In that way peers (phones) would register to kamailio, which would load balancing calls between asterisk servers and pass calls from asterisks to provider? Thx again!

    ReplyDelete
  5. Hello,

    I'm trying to setup Kamailio and Asterisk on the samebox with Kamailio listening on a public + private IP and asterisk only on private IP.

    Unfortunately I'm unable to get working as expected. We need somebody get us an hand !
    Please contact me at scramattegmailcom

    Best regards

    ReplyDelete
  6. Hello Gohar...i tested this more than one time and i'm receiving the same error message in asterisk
    ...................................................................................
    [2013-10-16 05:20:04] ERROR[3216][C-0000002c]: netsock2.c:269 ast_sockaddr_resolve: getaddrinfo("192.168.1.80192.168.1.80", "(null)", ...): Name or service not known
    [2013-10-16 05:20:04] WARNING[3216][C-0000002c]: chan_sip.c:10873 process_sdp_c: Unable to lookup RTP Audio host in c= line, 'IN IP4 192.168.1.80192.168.1.80'
    [2013-10-16 05:20:04] WARNING[3216][C-0000002c]: chan_sip.c:10464 process_sdp: Insufficient information in SDP (c=)...
    ..............................................................................
    So help me plz to solve this issue...

    ReplyDelete
    Replies
    1. There should be more then one usage od rtpproxy_manage() in Your route, so when You use It second time it add IP to c=IN of SDP. Only place where rtpproxy_manage() should be is route[RTPPROXY].

      Delete
    2. Try to remove nat_uac_test("19") from route[NATMANAGE] so You will allways be treated like behind NAT, You will see in kamctl ul show -> Cflag:: 64.

      Delete
  7. Hi Gohar,

    Thanks for a detailed and informative descriptions of the setup. I'm also trying to setup similar network, without the LB for this time.

    I'm running into an issue, I'm not sure whether you've seen this yourselves. Please share some pointers. My network is:

    clients <--> Public IP(Kamailio/RTPProxy)10.1.128.11 <--> 10.1.128.34 (Freeswitch)

    The 200 OK response from Freeswitch (on the way back from called party to caller) to Kamailio is shown below. Notice the Contact header URI host part contains Freeswitch Private IP (10.1.128.34). Kamailio suppose to change that to Public IP before forwarding the 200 OK (copied below) to Caller in public domain. But. it's not. As a result, ACK from Caller is not reaching back to Kamailio.

    How did you or anybody out there using Kamailio resolve this problem? If needed, I can copy/paste my kamailio.cfg.

    SIP 200 OK ->

    Via: SIP/2.0/UDP 10.1.128.11;branch=z9hG4bKa7ea.4013d9881c1b7fe7b4c6c0f0e8f9d6b6.0
    Via: SIP/2.0/UDP :5060;rport=5060;branch=z9hG4bK-383736-9b4621118533d3ccea17992738433249
    Record-Route:
    Record-Route: ;r2=on;lr=on;ftag=791b5ae3;nat=yes>
    From: \"Dipak Biswas\" >;tag=791b5ae3
    To: >;tag=atXF5443gQj9p
    Call-ID: 20d5d6d366fcb06c259a0895b3e44b52@0:0:0:0:0:0:0:0
    CSeq: 2 INVITE
    Contact:
    User-Agent: FreeSWITCH mod_sofia/1.4.2+git~20140108T200418Z~d8fc8469b4~64bit
    Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY
    Supported: timer, precondition, path, replaces
    Allow-Events: talk, hold, conference, refer
    Content-Type: application/sdp
    Content-Disposition: session
    Content-Length: 269


    Thanks,
    Dipak

    ReplyDelete
    Replies
    1. Hi dipak,
      We are having same issue. Were you able to resolve it? Would you care to share how?

      Delete
    2. Hello,
      We are having the same problem as you described here. Did you find a solution?
      Thanks,
      Emmanuel

      Delete
  8. Hello Ahmed,

    In your setup, how do I manage users login/password? by kamailio or Asterisk?
    I see only one peer in your Asterisk configuration.
    I'm a little lost. :-)

    How to set up this configuration with a Ast2Billing system or users are managed by 1 SIP user (A, B, etc) = 1 SIP peer/friend in asterisk.

    Thank you,
    Mickael

    ReplyDelete
    Replies
    1. Dear Mickael, In my example users are to be managed in Kamailio DB,they'll get registered at Kamailio and Asterisk give services only for Media level stuff.

      For setting up with A2billing you'll need to change this approach and see the Kamailio Asipto blog and integrate the A2billing SIP user table with kamailio directly and let the rest of the DB be used by asterisk(s). That way from A2billing Web-Panel you'll be able to manage SIP users/routes/LCR etc and Kamailio will be the only visible component of your project for each SIP endpoint.

      Delete
  9. Hello, I trying to integrate this scheme on my deploy. My problem is sending valid ACK from called party to Asterisk through Kamailio. When I recieve OK message Contact header contains private IP of asterisk server, so ACK try sends back to private ip of asterisk server. Offcourse it is wrong, because private ip is reacheble only through Kamailio.

    I've rtied this:
    onreply_route[MANAGE_REPLY] {
    xdbg("incoming reply\n");

    if(status=~"[12][0-9][0-9]")
    {


    if(ds_is_from_list("1"))
    {
    xlog("L_INFO", "Trying to change CONTACT FIELD\n");
    remove_hf("Contact");
    $avp(contact)="sip:"+$tU+"@PRO.XY.PUB.IP:5060";
    insert_hf("Contact:<$avp(contact)>\r\n","Call-ID");

    }
    }
    }

    But it has no shanges with Contact (so strange, but I've read - it bug)

    ReplyDelete
    Replies
    1. Hello. Were ever able to solve this?

      Delete
  10. Hi
    Thanks for all the details, I currently have Kamailio 4.1 installed, I have tried to paste the RTPProxy control section in to my cfg file, however service could not start.
    Currently I can make calls however I have no voice on both sides.
    I got a PCAP that I can share, there is one strange IP in pcap that I am not sure about.
    Any hints for why I can not hear anything or paste the section above to my cfg ?
    link to pcap https://www.dropbox.com/s/d6l1h34w6z54kkm/rtp-calls.zip?dl=0

    ReplyDelete
    Replies
    1. Everything look fine in terms of RTPproxy configs, there is no media coming from any of the side and what Im finding interesting is that the originator of this call has set SDP attricbite "a=receive only".
      Try changing your softphone, also see if there are any firewalls on your Kamailio server or at the either legs.

      which IP you're not sure about. Need to know more. Contact me on private email plz.

      Delete
  11. Kindly can you pls guide with the below

    Kamailio - 4.2.2 ( SIP server )
    Rtpproxy - Git Compiled ( miconda patched version )

    Issue:
    Remote NAT Call
    Bria Rmt Iphone SIP Extn (3G) ----> Kamailio Server -----> Desktop Bria Client ( Wifi )

    Audio and Video packets are sent from iPhone to desktop client .. but nothing otherway

    Thanks
    Chirag A
    chirag_ja@yahoo.co.in

    ReplyDelete
  12. Configuración de proxy (servidor VoIP de contrato) en ruters con fxo.

    Hola, como puedo especificar la dirección de la llamadas, si me llaman por el proxy las puedo mandar a los fxs, he visto que a veces el srp cuando recibe llamadas hace peticiones sip y rtp, lo que no se es por que no puedo identificar que pasa, creo que si contrato un número IP puedo hacer sonar los fxs pero desconozco que pasará con esos paquetes sip, creo que hay configuracion sip en el pstn y enable ip equivale a los sipura voip to pstn o algo así pero cada vez que consigo hacer algo el equipo pierde configuraciones o tal vez esté pasando pr varias centrales en el fxo y por esto no acaba de funcionar el adaptador del IOS cisco y no se volver a la primera central, o algo así me he esperado pero nada no detecta el fallo y no va, sobre todo suele perder tonos en el fxs y llamadas entrantes, y a veces el tono en la fxo.
    El proxy asterisk (servidor en mac) me enseña esto, bueno te deja comprobar funcionalidades para mandar llamadas entre oficinas o ver que le pasa a tu telefono SIP.

    SIP/2.0 200 OK
    To: ;tag=afa6e570d2160c87i0
    From: "asterisk" ;tag=as482fd221
    CALL-ID: 44ccef1a116545094de6154d49b71fdd@192.168.1.105:5060
    CSeq: 102 OPTIONS
    Via: SIP/2.0/UDP 192.168.1.105:5060;branch=z9hG4bK064d78f0
    Server: Cisco/SRP547-1.2.6(003)
    Content-Length: 0
    Allow: ACK, BYE, CANCEL, INFO, INVITE, NOTIFY, OPTIONS, REFER
    Supported: x-sipura, replaces
    Accept-Language: en


    GREAT DAY!!

    ReplyDelete
    Replies
    1. I couldn't understand the problem well, kindly share some personal contact info so I can hear you out and make some recommendations.

      Delete
  13. Hi this is such a great Blog,
    i am new to Kamailio, but do have experience in asterisk. if i am doing a multicast paging to Kamailio from one asterisk server, is it possible to send this rtp to multiple asterisk servers via SIP channels?

    ReplyDelete
  14. Thats definitely possible but extar code would be required such that kamailio at the initial invite understands that rtpproxy dont need to be engaged since RTPs are flowing within the "Asterisk" subnet directly. Similarly the INVITE needs to be sent to the target asterisk(s)>

    in simple words "it depends on the call flow scenario"

    ReplyDelete
  15. user1---joins--->(asterisk1 conference)---Page(multicastrtp)--->multicast group------->(asterisk2 conference room 2000 + asterisk3 conference room 3000 +asterisk4 conference 4000)

    the above is my scenario, in simple word i need to send multicast rtp from one conference (asterisk) to n-1 asterisk conference rooms.

    Please let me know how we can approach this with the help of kamailio and asterisk


    the above

    ReplyDelete
    Replies
    1. Sounds like an ambitious plan for a huge audio conf system.
      Well again, share how that Page(multicastrtp) is dialled form asterisk ?

      kamailio is only going to get the INVITE find where it needs to be routed to and relay it there. the SDP if needs to be modified for RTPproxy or not is again a configurable area for this.

      Delete