Saturday, April 25, 2009

RTPProxy 1.2.x Installation & Integration with OpenSIPS 1.5x

Before we start any thing, we need to know where we stand. By knowing current status, we could save us lot of headaches and time. Organization is the key to an effecient solution.

Lets first consider some questions about the server you have in place!!!

If you have public IP address for your server then don't worry about comments. If you don't then you have to have a way for a dynamic IP (from your ISP provider) to be resolved. Register with http://www.dyndns.com/ which woulld allow your dynamic IP to be resolved. OpenSIPS has to be on Static IP so you are listening on a specific address but your domain name needs to be resolved to your dynamic IP.

Step 01:
We will install RTP proxy for audio devices since softphone doesn't have media plug-ins; also if you have dynamic IP (from your ISP provider) then install DynDNS Update Clients "ddclient" for dyndns to automatically update the ip address when it changes

Link to ddclient installation instructions:
http://mexpolk.wordpress.com/2008/01/29/ubuntu-gutsy-dyndns-client-setup/

$ sudo apt-get install ssh libio-socket-ssl-perl
$ sudo apt-get install ddclient



Step 02:
@@@@ Server install RTPProxy 03/01/2009 @@@@
Configure Router for the Ports to be used by rtpproxy by opening them first (Read Consideration at the end of this article).

-- Use dpkg command to list installed software "dpkg –get-selections"

$ mkdir /backup
$ dpkg --get-selections > /backup/installed-software.log


Basic steps...

Code:
$ cd /usr/src
$ wget http://b2bua.org/chrome/site/rtpproxy-1.2.0.tar.gz
$ tar -xzvf rtpproxy-1.2.0.tar.gz

Change to the directory and install the program .
Code:
$ cd rtpproxy-1.2
$ ./configure
$ make
$ make install


Create a system user with no privileges and start the daemon running
Code:
$ adduser rtpproxy -d /home/rtpproxy -s /bin/false
$ rtpproxy -u rtpproxy

Now rtpproxy should be running and if you check in /var/run you should see rtpproxy.sock and rtpproxy.pid

Consideration:
Creating the user rtpproxy was not essential, you can run the daemon under whatever user you are logged in as by simply typing rtpproxy at the command but I read that it is safe practice to run the daemon under a non privileged user. (Maybe someone can comment on the linux user I added. I am not 100% on the security of the user added with no password but the way I understand it the user cannot access the system until a password is created.)

By default rtpproxy uses UDP ports 35000-65000 and these should be opened any firewalls in front of rtpproxy.

The Remote Control Mode can be activated by starting RTP Proxy with `-s' command line argument:

$ rtpproxy -s udp:address:port

Arguments: address is either IPv4 or IPv6 local address at which command should be accepted or "*" if rtpproxy should accept commands at all local interfaces; port is UDP port, if omitted port 22222 is used.

If RTPproxy is already running use force_sock function as shown below:
modparam("nathelper", "force_socket", "udp:localhost:22222")

Running Manually:
$ rtpproxy -F -l your-public-ip -s udp:localhost:port-no

e.g. $ rtpproxy -F -l 127.0.0.1 -s udp:192.168.1.2:9000

if above command is used to start rtpproxy then change your opensips.cfg file like this...
modparam("nathelper", "rtpproxy_sock", "udp:127.0.0.1:port-no")
modparam("nathelper", "force_socket", "udp:localhost:port-no")

Followings are examples for starting manually with user parameter...
$ rtpproxy -l 192.168.1.2 -s udp:127.0.0.1:50000 -u usrname &
OR
$ rtpproxy -s udp:127.0.0.1:50000 -f -u opensips -l 192.168.1.2 &


WARNING: command protocol contains no security or authentication measures, so that you should be using other means to secure RTP Proxy, such as firewall or even better a VPN between machine running RTP Proxy and machine which runs a software that controls it.

I have OpenSIPS operating successfully before installing RTPProxy

Check if process is running with the following command...

Code:
# ps axw /bin/egrep rtp
OR
# netstat -axep grep rtpproxy


Sample config file for RTP proxy Integration with OpenSIPS 1.5.x
#
# $Id: nathelper.cfg 5875 2009-07-15 19:05:20Z bogdan_iancu $
#
# simple quick-start config script including nathelper support
# This default script includes nathelper support. To make it work
# you will also have to install Maxim's RTP proxy. The proxy is enforced
# if one of the parties is behind a NAT.
#
# If you have an endpoing in the public internet which is known to
# support symmetric RTP (Cisco PSTN gateway or voicemail, for example),
# then you don't have to force RTP proxy. If you don't want to enforce
# RTP proxy for some destinations than simply use t_relay() instead of
# route(1)
#
# Sections marked with !! Nathelper contain modifications for nathelper
#
# NOTE !! This config is EXPERIMENTAL !
#
# @@@ There are additional changes made by Rookie which is
# @@@ not functional yet. Its giving only one way audio because
# @@@ RTP packets are being lost...
#
####
###
##
#
# -- Global Parameters
#
##
###
####
/* uncomment and configure the following line if you want opensips to
bind on a specific interface/port/proto (default bind on all available)
*/

children = 8
debug = 6 # debug level (cmd line: -dddddddddd)
fork = yes

group = "opensips"
user = "opensips"
/* uncomment the next line to disable TCP (default on) */
#disable_tcp=yes
disable_tcp = no

log_facility = LOG_LOCAL0 # LOG_DAEMON
log_stderror = yes # (cmd line: -E)
tcp_children = 6

check_via=no # (cmd. line: -v)
dns=no # (cmd. line: -r)
rev_dns=no # (cmd. line: -R)


/* uncomment the next line to enable the auto temporary blacklisting of
not available destinations (default disabled) */
#disable_dns_blacklist=no

/* uncomment the next line to enable IPv6 lookup after IPv4 dns
lookup failures (default disabled) */
#dns_try_ipv6=yes

/* uncomment the next line to disable the auto discovery of local aliases
based on revers DNS on IPs (default on) */
#auto_aliases=no

/* uncomment the following lines to enable TLS support (default off) */
#disable_tls = no
#listen = tls:your_IP:5061
#tls_verify_server = 1
#tls_verify_client = 1
#tls_require_client_certificate = 0
#tls_method = TLSv1
#tls_certificate = "/usr/local/etc/opensips/tls/user/user-cert.pem"
#tls_private_key = "/usr/local/etc/opensips/tls/user/user-privkey.pem"
#tls_ca_list = "/usr/local/etc/opensips/tls/user/user-calist.pem"

port=5060

/* uncomment and configure the following line if you want opensips to
bind on a specific interface/port/proto (default bind on all available)
*/
listen=udp:mydomain.com:5060

#*** set module path
mpath="//lib64/opensips/modules/"


####
###
##
# Modules Section
# ```````````````
# Loading moduels and
# Setting module-specific parameters
##
###
####


# Uncomment this if you want to use SQL database
loadmodule "db_mysql.so"

loadmodule "signaling.so"
loadmodule "sl.so"
loadmodule "tm.so"
loadmodule "rr.so"
loadmodule "maxfwd.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "textops.so"
loadmodule "mi_fifo.so"

# !! Nathelper
loadmodule "nathelper.so"

#
#***
#
loadmodule "uri_db.so"
loadmodule "uri.so"
loadmodule "xlog.so"
loadmodule "acc.so"
#
#**
#


# Uncomment this if you want digest authentication
# db_mysql.so must be loaded !
loadmodule "auth.so"
loadmodule "auth_db.so"

/* uncomment next line for aliases support
NOTE: a DB (like db_mysql) module must be also loaded */
loadmodule "alias_db.so"

/* uncomment next line for multi-domain support
NOTE: a DB (like db_mysql) module must be also loaded
NOTE: be sure and enable multi-domain support in all used modules
(see "multi-module params" section ) */
loadmodule "domain.so"

#
#**
#
loadmodule "dialog.so"
loadmodule "avpops.so"

#loadmodule "drouting.so"
#loadmodule "nat_traversal.so"
#loadmodule "mediaproxy.so"
#
#**
#

/* uncomment the next two lines for presence server support
NOTE: a DB (like db_mysql) module must be also loaded */
#loadmodule "presence.so"
#loadmodule "presence_xml.so"


####
###
##
# ----------------- setting module-specific parameters ---------------
##
###
####

# ----- mi_fifo params -----
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")

#**
modparam("mi_fifo", "fifo_mode", 0660)
modparam("mi_fifo", "fifo_group", "opensips")
modparam("mi_fifo", "fifo_user", "opensips")
modparam("mi_fifo", "reply_dir", "/tmp/")
modparam("mi_fifo", "reply_indent", "\t")


# ----- registrar params -----
modparam("registrar", "method_filtering", 1)

/* uncomment the next line to disable parallel forking via location */
# modparam("registrar", "append_branches", 0)
/* uncomment the next line not to allow more than 10 contacts per AOR */
#modparam("registrar", "max_contacts", 10)

# -- usrloc params --
#modparam("usrloc", "db_mode", 0)
# Uncomment this if you want to use SQL database
# for persistent storage and comment the previous line
modparam("usrloc", "db_mode", 2)
modparam("usrloc", "db_url",
"mysql://opensips:opensipsrw@localhost/opensips")

modparam("usrloc", "user_column", "username")
modparam("usrloc", "domain_column", "domain")
modparam("usrloc", "contact_column", "contact")
modparam("usrloc", "expires_column", "expires")
modparam("usrloc", "q_column", "q")
modparam("usrloc", "callid_column", "callid")
modparam("usrloc", "cseq_column", "cseq")
modparam("usrloc", "methods_column", "methods")
modparam("usrloc", "flags_column", "flags")
modparam("usrloc", "user_agent_column", "user_agent")
modparam("usrloc", "received_column", "received")
modparam("usrloc", "socket_column", "socket")
modparam("usrloc", "use_domain", 0)
modparam("usrloc", "desc_time_order", 0)
modparam("usrloc", "timer_interval", 60)
modparam("usrloc", "matching_mode", 0)

# ----- uri_db params -----
/* by default we disable the DB support in the module as we do not need it
in this configuration */
modparam("uri_db", "use_uri_table", 0)
modparam("uri_db", "db_url", "")


# -- auth db params --
# Uncomment if you are using auth module
modparam("auth_db", "calculate_ha1", yes)

#
# If you set "calculate_ha1" parameter to yes (which true in this config),
# uncomment also the following parameter)
modparam("auth_db", "password_column", "password")
modparam("auth_db", "db_url",
"mysql://opensips:opensipsrw@localhost/opensips")
modparam("auth_db", "load_credentials", "")


# ----- rr params -----
# add value to ;lr param to cope with most of the UAs
modparam("rr", "enable_full_lr", 1)
# do not append from tag to the RR (no need for this script)
modparam("rr", "append_fromtag", 0)

#
# !! Nathelper
#
modparam("usrloc", "nat_bflag", 6)
modparam("nathelper", "ping_nated_only", 1) # Ping only clients behind NAT
modparam("nathelper", "sipping_bflag", 8)
modparam("nathelper", "received_avp", "$avp(i:801)")

# RTPProxy setup
modparam("nathelper", "rtpproxy_sock", "udp:127.0.0.1:50100")
modparam("nathelper", "force_socket", "udp:localhost:50100")


# ----- acc params -----
/* what sepcial events should be accounted ? */
modparam("acc", "early_media", 1)
modparam("acc", "report_ack", 1)
modparam("acc", "report_cancels", 1)

/* by default ww do not adjust the direct of the sequential requests.
if you enable this parameter, be sure the enable "append_fromtag"
in "rr" module */
modparam("acc", "detect_direction", 0)

/* account triggers (flags) */
modparam("acc", "failed_transaction_flag", 3)
modparam("acc", "log_flag", 1)
modparam("acc", "log_missed_flag", 2)

/* uncomment the following lines to enable DB accounting also */
modparam("acc", "db_flag", 1)
modparam("acc", "db_missed_flag", 2)


#
# ----- multi-module params -----
/* uncomment the following line if you want to enable multi-domain support in the modules (dafault off) */
#modparam("alias_dbauth_dbusrlocuri_db", "use_domain", 1)

# ----- alias_db params -----
/* uncomment the following lines if you want to enable the DB based
aliases */
modparam("alias_db", "db_url",
"mysql://opensips:opensipsrw@localhost/opensips")


# ----- domain params -----
/* uncomment the following lines to enable multi-domain detection support */
modparam("domain", "db_url",
"mysql://opensips:opensipsrw@localhost/opensips")
modparam("domain", "db_mode", 1) # Use caching

#**
modparam("domain", "domain_table", "domain")
modparam("domain", "domain_col", "domain")

#
# ------- dialog --------
#**
modparam("dialog", "db_mode", 1)
modparam("dialog", "db_update_period", 30)
modparam("dialog", "dlg_flag", 4)
modparam("dialog", "dlg_match_mode", 1)

#
# --> avpops params -----
#**
modparam("avpops", "avp_table", "usr_preferences")
modparam("avpops", "use_domain", 1)


# ************
# ----- presence params -----
/* uncomment the following lines if you want to enable presence */
#modparam("presencepresence_xml", "db_url",
# "mysql://opensips:opensipsrw@localhost/opensips")
#modparam("presence_xml", "force_active", 1)
#modparam("presence", "server_address", "sip:192.168.1.2:5060")


#*** MySQL DB ***
modparam("dialogavpopsuri_db", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")


###
##
# -- MAIN request routing logic
##
###


route{
#
# -- 1 -- Request Validation
#
xlog("L_INFO", "New request - Request/failure/branch routes: M=$rm RURI=$ru F=$fu T=$tu IP=$si ID=$ci\n");

# initial sanity checks -- messages with
# max_forwards==0, or excessively long requests
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483","Too Many Hops...");
exit;
};
if (msg:len >= 2048 ) {
sl_send_reply("513", "Message too big...");
exit;
};

#
# -- 2 -- Routing Preprocessing
#
xlog("L_INFO", "MsgFlag:[$mf] \n");

# Some systems (like Asterisk) use OPTIONS as a kind of "ping", than we
# answer it with 200 OK.
if (method == "OPTIONS") {
sl_send_reply("200", "OK");
return;
};


# !! Nathelper
# Special handling for NATed clients; first, NAT test is
# executed: it looks for via!=received and RFC1918 addresses
# in Contact (may fail if line-folding is used); also,
# the received test should, if completed, should check all
# vias for rpesence of received
if (nat_uac_test("3")) {
# Allow RR-ed requests, as these may indicate that
# a NAT-enabled proxy takes care of it; unless it is
# a REGISTER

if (is_method("REGISTER") !is_present_hf("Record-Route")) {
log("LOG:Someone trying to register from private IP, rewriting\n");
# This will work only for user agents that support symmetric
# communication. We tested quite many of them and majority is
# smart enough to be symmetric. In some phones it takes a
# configuration option. With Cisco 7960, it is called
# NAT_Enable=Yes, with kphone it is called "symmetric media" and
# "symmetric signalling".

# Rewrite contact with source IP of signalling
fix_nated_contact();
if ( is_method("INVITE") ) {
fix_nated_sdp("1"); # Add direction=active to SDP
};
force_rport(); # Add rport parameter to topmost Via
setbflag(6); # Mark as NATed

# if you want sip nat pinging
setbflag(8);
};
};

# subsequent messages withing a dialog should take the
# path determined by record-routing
if (loose_route()) {
# mark routing logic in request
append_hf("P-hint: rr-enforced\r\n");
route(1);
exit;
};

# we record-route all messages -- to make sure that
# subsequent messages will go through our proxy; that's
# particularly good if upstream and downstream entities
# use different transport protocol
if (!is_method("REGISTER"))
record_route();

if (!uri==myself) {
# mark routing logic in request
append_hf("P-hint: outbound\r\n");
route(1);
exit;
};

# if the request is for other domain use UsrLoc
# (in case, it does not work, use the following command
# with proper names and addresses in it)
if (uri==myself) {

if (is_method("REGISTER")) {

# Uncomment this if you want to use digest authentication
#if (!www_authorize("siphub.org", "subscriber")) {
# www_challenge("siphub.org", "0");
# return;
#};

save("location");
exit;
};

lookup("aliases");
if (!uri==myself) {
append_hf("P-hint: outbound alias\r\n");
route(1);
exit;
};

# native SIP destinations are handled using our USRLOC DB
if (!lookup("location")) {
sl_send_reply("404", "Not Found");
exit;
};
};
append_hf("P-hint: usrloc applied\r\n");
route(1);
}

route[1]
{
# !! Nathelper
if (uri=~"[@:](192\.168\.10\.172\.(1[6-9]2[0-9]3[0-1])\.)" && !search("^Route:")){
sl_send_reply("479", "We don't forward to private IP addresses");
exit;
};

# if client or server know to be behind a NAT, enable relay
if (isbflagset(6)) {
force_rtp_proxy();
};

# NAT processing of replies; apply to all transactions (for example,
# re-INVITEs from public to private UA are hard to identify as
# NATed at the moment of request processing); look at replies
t_on_reply("1");

# send it out now; use stateful forwarding as it works reliably
# even for UDP2TCP
if (!t_relay()) {
sl_reply_error();
};
}

# !! Nathelper
onreply_route[1] {
# NATed transaction ?
if (isbflagset(6) && status =~ "(183)2[0-9][0-9]") {
fix_nated_contact();
force_rtp_proxy();
# otherwise, is it a transaction behind a NAT and we did not
# know at time of request processing ? (RFC1918 contacts)
} else if (nat_uac_test("1")) {
fix_nated_contact();
};
}

18 comments:

Amit Aggarwal said...

By Dynamic DNS you mean for softphone or you are using dynamic DNS for your OPENSIPS server?

Khan said...

If you have public IP address for your server then don't worry about those comments. If you don't then you have to have a way for a dynamic IP (from your ISP provider) to be resolved. Register with http://www.dyndns.com/ which woulld allow your dynamic IP to be resolved. OpenSIPS has to be on Static IP so you are listening on a specific address but your domain name needs to be resolved to your dynamic IP.

Amit Aggarwal said...

Khan,

What do you think willbe the best solution if I don't have access to router for NAT transversal problem. During RTP proxy details you mention open router ports but I don't have the access to router ans cannot have changes at router.

Khan said...

Amit,
I don't know if you can run server without having access to ports. I believe you can check for the ports if they are open on your connection by searching on web, there is website which allow you to see what ports are blocked. You might have regional blocks based on what country you are trying from such as pakistan, UAE etc block voip trafic. If this is a case then you need more complexed solution than just simple configuration.

Amit Aggarwal said...
This comment has been removed by the author.
Amit Aggarwal said...

I got this error while running opensips and it was gone when i conmmented out the following line in opensips.cfg file :
#*** MySQL DB ***
modparam("dialogavpopsuri_db", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
. I am case I have some SIP phone (X-lite ans cisc0 7960) behind NAT and OPENSIPS on public IP Address. I can make call (two way) when one phone is on public address and other behind NAT but when try call between two phone behind same NAT there in no audio in either direction. Please bare with me I am handling this problem for first time

Khan said...

Amit,
There is typo in that statement, its suppose to be an | between dialog, avpops, and uri_db but somehow html has supressed those, please look at the script again now its showing. fix your config and un-comment out that statement.
You can also use it to make 3 septate statements for each module.

following line should be changed to:
modparam("dialog|avpops|uri_db", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")

Amit Aggarwal said...

You said earlier that you get one way Audio in that case both of your UA's(phones) were behind NAT? I my case i get one way audio when one UA is behind NAT and one is on public. If both of my phones are behind same NAT i get no audio at all. To this my assumption is that RTPproxy is not working!

Khan said...

Amit,
In my case when I have both UA behind NAT then i get one way audio within my network i get audio fine. You have to check which port you are forcing in CFG file, run the RTPproxy manually on the same IP's and Ports. Try to capture trace through WireShark and analyze RTP packets.

ezz said...

Hi, thanks for posting this.. I came across your web site as I was searching for Opensips and natting.. I have both my opensips and clients behind NAT. I'm trying to configure the opensips and I used your config file. when I start opensips I get the error message for this line:

#if (is_method("REGISTER") !is_present_hf("Record-Route")) log("LOG:Someone trying to register from private IP, rewriting\n");

if I remove it then opensips starts fine but still can't register my phone though... is anything missing there?

Thanks

sip said...

hey Rookie,

do you provide support for rtp proxy + oopensips

let me know
sipsalleyatgmail.com

Khan said...

I can try to help but as far as professionally; my answer is no. I am into DB Analysis and Design. VoIP is my hobby. Let me know the nature of your problem and I will try to help.

Khan said...

Hey ezz, I'm sorry; I'm out of loop for a little while got some projects hogging all my time. Hope you had answer. Try the OpenSIPS mailing server for the problem. My apologies :(

Raza said...

Have you any idea about how to configure rtpproxy with sippy b2bua?

Khan said...

I am sorry, It has been long time since I worked with it and I never experiment with B2BUA :(

AwisePilot said...

Great information on getting started. Roza I am attempting to use b2bua and rtpproxy.

Unknown said...

Great article! thank you very much.
Why doesn't the rtpproxy pass DTMFs? Is there any configuration for that?

Khan said...

I apologize for tardiness but it has been long time since I touched the VoIP platform; I wish I could answer your question, but I have no clue at this point. If you find the answer, please do post it here