Kamailio Behind NAT

Kamailio
Kamailio 4

After returning home from AstriCon 10, I decided to start-up a new server and see how long it would take me to run a working Kamailio server behind NAT (on a private IP). Bottom line? About 30 minutes.

I was lucky to help staff the Kamailio booth this year and was honored to help so many other VoIP professionals (and enthusiasts) with their questions about Kamailio, so without further ado…

What is Kamailio?

Kamailio (OpenSER) is an open source SIP server capable of handling thousands of call set-ups per second. Some amazing features include: 

  • Secure communication via TLS
  • Load Balancing
  • WebSocket support for WebRTC
  • failover
  • Security
  • and mucho mas

 Who should use Kamailio?

If you’re running fewer than 100 phones, you  most likely won’t have a need for Kamailio — unless you want failover, enhanced security, WebRTC, or one of the other Kamailio features.

I use Kamailio to help protect my systems from scanners, brute force SIP attacks, and other fun aspects of running business on the Interwebs.

… but … I digress …

Running Kamailio behind NAT

Many of us don’t have access to large numbers of public IP addresses. Some of us also like running systems on private IP addresses for personal reasons.

In the past (and still today), it was recommended that you run Kamailio on a public IP address. Regardless of the reason, with a patched rtpproxy and an advertised public IP address, you can have Kamailio running on a private IP address very quickly.

(NOTE: This tutorial was written for Kamailio 4.0 and an old version of RTPProxy. I recommend running the current version of both.)

Step 1: Install Kamailio

I chose to install Kamailio on CentOS. I’m not going to get into a religious war here on what OS you should use. Most of the development team of Kamailio use debian… I like CentOS, and that’s what I choose to deploy.

There’s an excellent tutorial for installing Kamailio posted on the main wiki: Install And Maintain Kamailio v4.0.x Version From GIT.

For CentOS, I first disable selinux, and then install some pre-reqs:

yum -y install gcc gcc-c++ bison openssl-devel libtermcap-devel ncurses-devel doxygen curl-devel newt-devel mlocate lynx tar wget nmap bzip2 unixODBC unixODBC-devel libtool-ltdl libtool-ltdl-devel mysql-connector-odbc mysql mysql-devel mysql-server flex libxml2 libxml2-devel pcre pcre-devel git

Some of these aren’t fully necessary for the deployment, but are good tools to have. I also generally install the development tools group as well.

yum groupinstall "Development Tools"

Once everything is ready (a reboot doesn’t hurt), it’s time to download and install Kamailio.

mkdir -p /usr/local/src/kamailio-4.0
cd /usr/local/src/kamailio-4.0
git clone --depth 1 git://git.sip-router.org/sip-router kamailio
cd kamailio
git checkout -b 4.0 origin/4.0
make cfg

Next, open modules.1st. I use vi. You can use whatever you’d like.

vi modules.1st

Find the section that says include_modules and add db_mysql. It will look like:

include_modules= db_mysql

Save the file… and let’s continue.

make all
make install

Step 2: Create the Database

Open the kamctlrc file, uncomment the mysql database reference, and change the default passwords:

vi /usr/local/etc/kamailio/kamctlrc
DBENGINE=MYSQL

Save the file and run the following command:

/usr/local/sbin/kamdbctl create

This creates the kamailio database for you.

Step 3: Modify the Kamailio config file

Kamailio builds a default file for you. We’re going to quickly modify it to get this demo working.

vi /usr/local/etc/kamailio/kamailio.cfg

Insert the following after the #!Kamailio line:

#!define WITH_MYSQL
#!define WITH_AUTH
#!define WITH_USRLOCDB
#!define WITH_ANTIFLOOD
#!define WITH_NAT

This adds a minimal amount of protection to your system (with ANTIFLOOD) and allows you to authenticate users to your system. It will also start the ball rolling for NATted communication.

Next, find the line that says: #!define DBURL “mysql://kamailio:kamailiorw@localhost/kamailio” and replace with:

#!define DBURL "mysql://USERNAME:PASSWORD@localhost/kamailio"

Next, find the line that says: #listen=udp:10.0.0.10:5060 and underneath it, add:

listen=udp:PRIVATEIP:5060 advertise PUBLICIP:5060

Save the file. Smile.

The advertise function here is key for running behind NAT along with…

Step the Fourth: Install the Patched rtpproxy

(NOTE: If you use the current version of rtpproxy, you won’t need to install the patch– it includes the advertise option)

rtpproxy is an open source program written by Sippy Software and available from their website, rtpproxy.org. The current stable version of rtpproxy is 1.2.1 and is missing one awesome feature — the ability to use an advertised address.

Luckily there are programmers who have resolved this issue for us.

Back in 2009, Daniel Goepp posted a patch to RTPproxy to support putting rtpproxy behind NAT.

Another Daniel, Daniel-Constantin Mierla, posted a patched version of rtpproxy on github.

We’ll choose the github for this example. I downloaded as a zip file and installed.

unzip master.zip
cd rtpproxy-master
./configure
make all
make install

You now have a version of rtpproxy that will advertise a public IP from behind NAT.

The Fifth Step: Starting the services

Since you’re behind NAT, you’re most likely going to want to forward UDP port 5060 for SIP and a UDP port range for RTP from your firewall to your Kamailio server’s private IP. For this example, let’s use an RTP port range of 20,000 to 30,000. (you’ll take care of your firewall forwarding however is needed on your particular firewall)

Start rtpproxy with a set rtp port range and an advertised public IP:

rtpproxy -A PUBLICIP -F -l PRIVATEIP -m 20000 -M 30000 -s udp:*:7722 -d INFO

Next, start Kamailio

kamctl start

Step 6: Add some users, and make calls

Adding a user is simple:

kamctl add USERNAME PASSWORD

For example, you could run kamctl add qxork superhotyeni which would add the user qxork with a password of superhotyeni.

In Closing…

Kamailio is incredible software… it’s addictive and you start learning that SIP can become a really incredible tool to work with.

To know Kamailio is to know SIP.

And there’s the problem. To know SIP you must learn SIP and play with SIP.

Since most of us don’t have access to spare servers that we can put on a public IP, we’re stuck learning the system on a local NAT at the office or (more commonly) at the house.

Running Kamailio behind NAT allows you to learn, test, and play with SIP. Now, there’s no excuse… let’s start learning!

Additional Reading:
Need Help?

We’re a friendly community. We also have cookies.

30 Replies to “Kamailio Behind NAT”

  1. I first disable selinux

    Not a great start. I know SELinux can get annoying, but like UAC on Windows it’s better for all to do it right and work with SELinux rather than just telling people to turn off a useful security feature.

    Also…

    Some of us also like running systems on private IP addresses for personal reasons.

    Mind explaining? The problems with NAT and thus private addresses for internet communications are well known, especially to those of us dealing with SIP. What possible reason could you have to want to keep dealing with those headaches?

    I personally welcome the exhaustion of IPv4, the faster we get IPv6 everywhere the sooner NAT can be eliminated.

    1. Hi Sean,

      There’s an irony in complaining that turning off selinux is not a great start while private ips / NAT be completely eliminated.

      Not a great start. I know SELinux can get annoying, but like UAC on Windows it’s better for all to do it right and work with SELinux rather than just telling people to turn off a useful security feature.

      I guess this depends on what your definition of useful is. There are other ways to secure your system without adding the overhead of selinux.

      Much like choosing an OS, there’s pros and cons. For me, I choose to handle security with firewalls and other methods; avoiding selinux for servers.

      The problems with NAT and thus private addresses for internet communications are well known, especially to those of us dealing with SIP. What possible reason could you have to want to keep dealing with those headaches?

      There are many ways of dealing with NAT; especially with SIP. Although it’s not fun to deal with NAT and SIP, tools included with Kamailio, FreeSWITCH, and Asterisk really deal with this nicely. Benefits of a private IP include aspects of security; such as obscuration, independent numbering with simplified routing, load balancing, and more.

      The thought of changing a provider and renumbering a large network is ridiculous. It’s resolved with NAT and exists with ipv6.

      Of course, NAT absolutely does not provide security in of itself. It’s a tool that can help with security… which brings me back to the ironic statement.

  2. Hello, congratulations for the tutorial, I have would be great that you can help me with Kamailio:
    1: I have a public ip connected to the router and from there I assigned 192.168.1.100 as Kamailio server
    2: The router has routed all traffic udp / tcp 5060 to 192.168.1.100 I also configured with NAT-A xxxx rtpproxy-F-l 192.168.1.100-m 20000-M 30000-s udp: *: 7722 INFO-d where xxxx is the router.
    Problem => 3: The devices can connect from anywhere but at the time of the voice call is transmitted.
    Problem => 4: Jitsi allows me to IM but nothing more

    Could you give me some advice I have exhausted all options, thanks.

  3. Yea, I am running in a virtual.

    I finally got the patch applied and re-compiled.

    Seems to work better.

    I did notice though if I stop kamailio, then start rtpproxy before kamailio I see high CPU. If I boot the server with kamailio starting at boot and then start rtpproxy after CPU is normal for rtpproxy.

    1. Please, I need help with getting the patch to work.

      I get errors when I run the patch. Your help will be most appreciated.

      ##> patch -p1 < patch-file
      patching file main.c
      Hunk #3 FAILED at 151.
      Hunk #4 FAILED at 177.
      2 out of 4 hunks FAILED — saving rejects to file main.c.rej
      patching file rtpp_command.c
      Hunk #1 FAILED at 201.
      1 out of 1 hunk FAILED — saving rejects to file rtpp_command.c.rej
      patching file rtpp_defines.h
      Hunk #1 FAILED at 103.
      1 out of 1 hunk FAILED — saving rejects to file rtpp_defines.h.rej

        1. I installed the github version rtpproxy-master following your instructions, but it was taking up all the CPU. My setup is on AWS. From your previous comments, I understand that running in a virtualized environment can result in high cpu consumption. Do you know of anyway to avoid this problem?

          Thanks.

  4. I am installed Kamailio with your tutorial (thanks!), and http://kb.asipto.com/asterisk:realtime:kamailio-4.0.x-asterisk-11.3.0-astdb

    I can’t dial form 101 to 102 peers, registered in Asterisk via Kamailio, but can listen VoiceMail greeting from Asterisk when got from kamailio SIP 404 Not found on dialing.

    Listening on
    udp: 192.168.182.23:5080 advertise PUB.LIC.IP.HERE:5080
    Aliases:
    udp: kamailio.localdomain:5080
    udp: localhost.localdomain:5080
    udp: localhost:5080
    udp: kamailio:5080
    *: PUB.LIC.IP.HERE:*
    *: PUB.LIC.HOSTNAME.HERE:*

    listen=udp:192.168.182.23:5080 advertise PUB.LIC.IP.HERE:5080

    SIP trace:

    http://pastebin.com/ZYsV7Rip

  5. Dear sir,

    Thanks for your tutorial. I’ve already completed follow your guide. But i meet a problem when running rtpproxy -A PUBLICIP -F -l PRIVATEIP -m 20000 -M 30000 -s udp:*:7722 -d INFO

    Message:
    rtpproxy: host2bindaddr: Name or service not known

    Could your please help me solve this issue.

    Thanks for your support.

    Best regards,
    Tung.

      1. Hi Fred,

        Thanks for your reply,

        We tried to do as your guide but it seems that our configuration is not good. We test with 2 phones and here are the result:
        1. Two phone can connect to each other.
        2. Two phone can only comunicate (speak and hear) to each other if they are in the same network. When we connect 3G – Wifi network, we cannot hear to each other.
        (We use linephone for test).

        Very please if you can help us setup and config our server sothat phones can contact in both 3G and wifi. Please help us as a freelancer if you have time.
        I’ll have some money to your training.

        Sorry if my English is not good. Please help us.

        I’m looking forwarding your reply.

        Thanks.
        Tung.

  6. Hi Frad,
    Thanks for Such a Nice Blog ,
    I will be thanks full you suggest how do we setup web-socket over SIP on Kamailio

    It would really help for me .

  7. Hello,

    Thank you for the post.

    I would like to ask you something.
    My scenario is an Asterisk and them a Kamailio

    I applied the path and it works fine, sdp info is rewrite with the public IP address.

    My INVITE: from kamailio to sip vendor
    ——————————————————

    v=0
    o=root 1857800054 1857800054 IN IP4 10.18.35.45
    s=Asterisk PBX 1.8.32.3
    c=IN IP4 10.18.35.45
    t=0 0
    m=audio 30036 RTP/AVP 8 101
    a=rtpmap:8 PCMA/8000
    a=rtpmap:101 telephone-event/8000
    a=fmtp:101 0-16
    a=ptime:20
    a=sendrecv
    a=nortpproxy:yes

    —————————————————————————————-
    So far works fine, the problem I see when the OK with SDP is received, Kamailio rewrites the public IP address from the vendor and inserts the “advertised” IP.

    My question is: Should Kamailio insert the advertised IP from Kamailio to Asterisk (or sip extensions registered in Kamailio) or should insert local Kamailio IP.

    OK With SDP received

    v=0
    o=HuaweiSoftX3000 33567120 33567121 IN IP4 10.18.35.45
    s=Sip Call
    c=IN IP4 10.18.35.45
    t=0 0
    m=audio 30078 RTP/AVP 8 101
    a=rtpmap:8 PCMA/8000
    a=rtpmap:101 telephone-event/8000
    a=ptime:20
    a=fmtp:101 0-15
    a=nortpproxy:yes

    1. This depends on multiple factors, and also how you’re calling the manage rtpproxy. Generally, if you use an advertised address and want to instead show an internal address, you’ll need to pass it in the manage command.

  8. Thank you for your previous post.

    I think in am on the right direction.

    Calls is established and I have two way audio.
    The problem starts when the callee (remote party) hangs up the call. The caller (Kamailio does not receive the BYE).

    I am inserting a contact alias in order to have public IP (8.8.8.8 as an example) advertised in contact.

    The problem is that internet router changes the source port and then vendor sends BYE to original port (5060) that is included in the contact alias and then router blocks the request.

    if (!add_contact_alias(“8.8.8.8”, “$Rp”, “udp”)) {
    xlog(“L_ERR”, “Error in aliasing contact $ct\n”);
    send_reply(“400”, “Bad request”);
    exit;
    }
    }

    ¿How can I include nat´d source port in the contact?

    Thank you

  9. Hi,

    I am attempting a similar setup. I have Kamailio connecting the calls fine, just no audio. When performing an RTP debug on the SIP server, I noticed it is not trying to send the RTP packets to Kamailio, but instead tries to connect RTP directly to user (phone). Do you know how I can explicitly make RTP go through Kamailio?

    1. If both phones are trying to send the media to each other, and you do not want this, then you can force a proxy of the media. Just before t_relay() the signalling to the second leg, use rtpproxy module’s function manage_rtpproxy().

Leave a Reply

Your email address will not be published. Required fields are marked *