This article continues on series of articles about the Kamailio 3.1.x SIP proxy server deployed on the debian lenny and its features. In previous articles we have focused on:
1) installing clear Kamailio 3.1.x server
2) adding of the Mysql support for persistance location storage
3) installing of the SIREMIS web management interface for our Kamailio server.
4) configuring the IM and presence service on Kamailio 3.1 - Howto
5) configuring the XCAP support for SIMPLE.
6) configuring TLS support
Now we will take a closer look on the NAT traversal solution with the usage of the Rtpproxy server.
1) Installed and working Kamailio (OpenSER) 3.1.0 server.
2) Installed and running rtpproxy server. For this guide (as you see at the end, rtpproxy 1.2.1 does not work, 1.1.2 does)
3) usrloc (user location) module of the kamailio loaded
Kamailio 3.1 has for the NAT traversal preconfigured zone block prepared for the the rtpproxy server usage. So open /etc/kamailio/kamailio.cfg and find lines starting with:
# *** To enable nat traversal execute: # - define WITH_NAT # - install RTPProxy: http://www.rtpproxy.org # - start RTPProxy: # rtpproxy -l _your_public_ip_ -s udp:localhost:7722
They recommends to define "WITH_NAT" directive and to install rtpproxy with recommended parameters. We have rtpproxy already installed, thus we need to define the zone block directive only
#!define WITH_NAT
Going next, in module loading part of the config file, we may find zone block:
#!ifdef WITH_NAT loadmodule "nathelper.so" loadmodule "rtpproxy.so" #!endif
which will load modules (nathelper and rtpproxy) required for the NAT traversal, conditional of the WITH_NAT directive defined. We did it in previous step, so following modules will be loaded during the next restart of the Kamailio server.
Going next, in module param section of the kamailio.cfg we will find zone block:
#!ifdef WITH_NAT # ----- rtpproxy params ----- modparam("rtpproxy", "rtpproxy_sock", "udp:127.0.0.1:7722") # ----- nathelper params ----- modparam("nathelper", "natping_interval", 30) modparam("nathelper", "ping_nated_only", 1) modparam("nathelper", "sipping_bflag", FLB_NATSIPPING) modparam("nathelper", "sipping_from", "sip:[email protected]") # params needed for NAT traversal in other modules modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)") modparam("usrloc", "nat_bflag", FLB_NATB) #!endif
This part of the Kamailio config file we have to modify slightly. Our topology is using the Kamamilio and the Rtpproxy running in the same machine, and they will communicate between each other using the localhost IP address. So, if we are using the Rtpproxy server with default configuration, we have to open /etc/default/rtpproxy file and uncomment following line regarding of udp socket, that will be sued for interconnection:
CONTROL_SOCK=udp:127.0.0.1:22222
and than we have to modify first modparam line from above kamailio.cfg block to reflect the actual rtpproxy configuration:
modparam("rtpproxy", "rtpproxy_sock", "udp:127.0.0.1:22222")
Next line of the configuration, modparam("nathelper", "natping_interval", 30) define in seconds how often NAT ping will be send to keep NAT binding opened, here 30second. We do not need to modify it.
Line modparam("nathelper", "ping_nated_only", 1) define, that only SIP UAs which are behind NAT will be pinged. We do not need to modify it.
Line modparam("nathelper", "sipping_bflag", FLB_NATSIPPING) define which branch flag of nat-ed client will be used for nat pinging. We do not need to modify it. By default the 7th flag is set and is named FLB_NATSIPPING, we may find it in ####### Defined Values ######### part of the kamailo.cfg
# - flags
# FLT_ - per transaction (message) flags
# FLB_ - per branch flags
#!define FLT_ACC 1
#!define FLT_ACCMISSED 2
#!define FLT_ACCFAILED 3
#!define FLT_NATS 5
#!define FLB_NATB 6
#!define FLB_NATSIPPING 7
Tutorial about Kamailio flags is available at the link. Currently there are 31 tags defined, which can be named (like here).
Next line modparam("nathelper", "sipping_from", "sip:[email protected]") I will change to reflect my server DNS name:
modparam("nathelper", "sipping_from", "sip:[email protected]")
Line modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)") define, I cited module documentation:
name of the Attribute-Value-Pair (AVP) used to store the URI containing the received IP, port, and protocol. The URI is created by fix_nated_register function of nathelper module and the attribute is then used by the registrar to store the received parameters. Do not forget to change the value of corresponding parameter in registrar module if you change the value of this parameter.
Line modparam("usrloc", "nat_bflag", FLB_NATB) tell to the usrloc module to save branch parameter, that will be used as the NAT marker (decide if the contact is or not natted). This is a branch flag and it will be imported and used by nathelper module.
The first routing logic which is working with NAT traversal is the route [NAT] called from the main route logic. route [NAT] detects if a caller is behind a NAT. It is used for all methods which are generated from an UAC.
# Caller NAT detection route route[NAT] { #!ifdef WITH_NAT force_rport(); if (nat_uac_test("19")) { if (method=="REGISTER") { fix_nated_register(); } else { fix_nated_contact(); } setflag(FLT_NATS); } #!endif return; }
Function force_rport() adds the rport parameter to the first Via header of the received message. Rport parameters cause that proxy will send subsequence responses back to this source port (this is the "public" port after NAT-ing).
Then inside of the logic test if UAC is behind NAT is done (nat_uac_test("19")), from the docu 19 = 1 + 2 + 16 (i.e.
1 - Contact header field is searched for occurrence of RFC1918 addresses.
2 - the "received" test is used: address in Via is compared against source IP address of signaling
4 - Top Most VIA is searched for occurrence of RFC1918 addresses
8 - SDP is searched for occurrence of RFC1918 addresses
16 - test if the source port is different from the port in Via
32 - test if the source IP address of signaling is a RFC1918 address
)
and if the SIP method is REGISTER, the function fix_nated_register() creates a URI consisting of the source IP, port, and protocol and stores the URI in an Attribute-Value-Pair ($avp(RECEIVED) in our case). The registrar will store the URI in the received column inside of the location table.
Otherwise the Contact header field of the SIP message will be rewritten to contain request's source address:port (fix_nated_contact()).
As the last step, the flag FLT_NATS is setted up to one as a mark that NATing is used.
During the UA registration the registrar have to adjust flags indicating that a client is behind a NAT and to save branch param. Registrar has to setup B flag also, which is used by the nathelper module.
Route logic executed during a registation is by default:
# Handle SIP registrations route[REGISTRAR] { if (is_method("REGISTER")) { if(isflagset(FLT_NATS)) { setbflag(FLB_NATB); # uncomment next line to do SIP NAT pinging ## setbflag(FLB_NATSIPPING); } if (!save("location")) sl_reply_error(); exit; } }
and we have to uncomment the line:
setbflag(FLB_NATSIPPING);
to start pinging the NAT performed by the nathelper module (performed if FLB_NATSIPPING is setted up).
The server during the registration phase check if the 5th flag is set (line isflagset(FLT_NATS)), and since it is (setted up in route[NAT]), as a next step the Branch flag named FLB_NATB is set (the 5th flag), together with the flag FLB_NATSIPPING (7th flag) (nat pinging required). Branch param will be saved to (usrloc) and logic execution is stopped.
The module responsible for working with Kamailio flags is KEx module.
This route logic is called few times:
From the NAT traversal point of view the logic setup the branch flag and if prerequsities for detecting NAT is fulfilled it call the rtpproxy logic
route[RELAY] {
#!ifdef WITH_NAT
if (check_route_param("nat=yes")) {
setbflag(FLB_NATB);
}
if (isflagset(FLT_NATS) || isbflagset(FLB_NATB)) {
route(RTPPROXY);
}
#!endif
/* example how to enable some additional event routes */
if (is_method("INVITE")) {
#t_on_branch("BRANCH_ONE");
t_on_reply("REPLY_ONE");
t_on_failure("FAIL_ONE");
}
if (!t_relay()) {
sl_reply_error();
}
exit;
}
The logic is called from the RELAY route and it is used to rewrite private addresses inside of the SDP body (force_rtp_proxy()) of the message or at the end of a call to close down a RTPproxy session.
# RTPProxy control route[RTPPROXY] { #!ifdef WITH_NAT if (is_method("BYE")) { unforce_rtp_proxy(); } else if (is_method("INVITE")){ force_rtp_proxy(); } if (!has_totag()) add_rr_param(";nat=yes"); #!endif return; }
This testing was done for the Kamailio 3.1 and the Rtpproxy 1.2.1
Usrloc record made for registration of the Client behind nat looks like:
AOR:: jan Contact:: sip:[email protected] Q= Expires:: 3441 Callid:: [email protected] Cseq:: 224 User-agent:: Twinkle/1.4.2 State:: CS_SYNC Flags:: 0 Cflag:: 0 Socket:: udp:158.193.139.51:5060 Methods:: 6111
the REGISTER method received from the UAC behind NAT contain private addresses. The registration process was sucessfull
REGISTER sip:ps.sip.uniza.sk SIP/2.0. Via: SIP/2.0/UDP 10.0.2.15;rport;branch=z9hG4bKwyecvlbs. Max-Forwards: 70. To: "jan" <sip:[email protected]>. From: "jan" <sip:[email protected]>;tag=hxwkx. Call-ID: [email protected]. CSeq: 224 REGISTER. Contact: <sip:[email protected]>;expires=3600. Authorization: Digest username="jan",realm="ps.sip.uniza.sk",nonce="TPiqzUz4qaGMhfAopOhr80LB7LZ22p1r",uri="sip:ps.sip.uniza.sk",response="b18c53a210525abb334cff1f28cc0fe7",algorithm=MD5. Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,PRACK,REFER,NOTIFY,SUBSCRIBE,INFO,MESSAGE. User-Agent: Twinkle/1.4.2. Content-Length: 0. . U 158.193.139.51:5060 -> 158.193.139.235:60361 SIP/2.0 200 OK. Via: SIP/2.0/UDP 10.0.2.15;rport=60361;branch=z9hG4bKwyecvlbs;received=158.193.139.235. To: "jan" <sip:[email protected]>;tag=f11c829fa10fd0f1cba4621773c131eb.1e7c. From: "jan" <sip:[email protected]>;tag=hxwkx. Call-ID: [email protected]. CSeq: 224 REGISTER. Contact: <sip:[email protected]>;expires=3600. Server: kamailio (3.1.0 (x86_64/linux)). Content-Length: 0.
Now we will start the kamailio with NAT support and we will observe the changes.
The Usrloc is changed a little be, Received parameter was added and the Cflag is changed:
AOR:: jan Contact:: sip:[email protected] Q= Expires:: 3586 Callid:: [email protected] Cseq:: 234 User-agent:: Twinkle/1.4.2 Received:: sip:158.193.139.235:62055 State:: CS_NEW Flags:: 0 Cflag:: 192 Socket:: udp:158.193.139.51:5060 Methods:: 6111
During of the register message exchange, inside of the 200 Ok message the received parameter is inserted
REGISTER sip:ps.sip.uniza.sk SIP/2.0. Via: SIP/2.0/UDP 10.0.2.15;rport;branch=z9hG4bKskrtfzbd. Max-Forwards: 70. To: "jan" <sip:[email protected]>. From: "jan" <sip:[email protected]>;tag=dohaq. Call-ID: [email protected]. CSeq: 234 REGISTER. Contact: <sip:[email protected]>;expires=3600. Authorization: Digest username="jan",realm="ps.sip.uniza.sk",nonce="TPitRkz4rBoh5k2qVS7QRyL9FjFXuI1Y",uri="sip:ps.sip.uniza.sk",response="d807146af45f4ce248738f6b7fe4d411",algorithm=MD5. Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,PRACK,REFER,NOTIFY,SUBSCRIBE,INFO,MESSAGE. User-Agent: Twinkle/1.4.2. Content-Length: 0. . U 158.193.139.51:5060 -> 158.193.139.235:62055 SIP/2.0 200 OK. Via: SIP/2.0/UDP 10.0.2.15;rport=62055;branch=z9hG4bKskrtfzbd;received=158.193.139.235. To: "jan" <sip:[email protected]>;tag=f11c829fa10fd0f1cba4621773c131eb.36d7. From: "jan" <sip:[email protected]>;tag=dohaq. Call-ID: [email protected]. CSeq: 234 REGISTER. Contact: <sip:[email protected]>;expires=3600;received="sip:158.193.139.235:62055". Server: kamailio (3.1.0 (x86_64/linux)). Content-Length: 0.
Registration was sucesfull (as usually).
The INVITE message arrived to the server, signalling works, media does't
T 158.193.139.192:49260 -> 158.193.139.51:5060 [AP] INVITE sip:[email protected] SIP/2.0. Via: SIP/2.0/TCP 158.193.139.192:49918;branch=z9hG4bK-d8754z-975d22393e6c4702-1---d8754z-;rport. Max-Forwards: 70. Contact: <sip:[email protected]:49260;transport=TCP>. To: <sip:[email protected]>. From: "jojo"<sip:[email protected]>;tag=73203c66. Call-ID: N2M1MTc4MzAyNjI4ZTViZTA1NDE5MjAzZDc4ZWU3NjA.. CSeq: 2 INVITE. Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO. Content-Type: application/sdp. Proxy-Authorization: Digest username="jojo",realm="ps.sip.uniza.sk",nonce="TPizQUz4shXsqLjd3BfmYyVrrljigrVn",uri="sip:[email protected]",response="60829a1aaccdd15f8d183c3f98f32277",algorithm=MD5. Supported: replaces. User-Agent: Bria Professional release 2.4 stamp 49381. Content-Length: 451. . v=0. o=- 5 2 IN IP4 158.193.139.192. s=CounterPath Bria Professional. c=IN IP4 158.193.139.192. t=0 0. m=audio 27460 RTP/AVP 107 119 100 106 0 98 8 18 101. a=fmtp:18 annexb=yes. a=fmtp:101 0-15. a=rtpmap:107 BV32/16000. a=rtpmap:119 BV32-FEC/16000. a=rtpmap:100 SPEEX/16000. a=rtpmap:106 SPEEX-FEC/16000. a=rtpmap:98 iLBC/8000. a=rtpmap:18 G729/8000. a=rtpmap:101 telephone-event/8000. a=sendrecv. a=x-rtp-session-id:8767743075B64036B830760C208977F5.
INVITE is redirected to the UA behind a NAT and is sent to 158.193.139.235:62055
U 158.193.139.51:5060 -> 158.193.139.235:62055 INVITE sip:[email protected] SIP/2.0. Record-Route: <sip:158.193.139.51;r2=on;lr=on;nat=yes>. Record-Route: <sip:158.193.139.51;transport=tcp;r2=on;lr=on;nat=yes>. Via: SIP/2.0/UDP 158.193.139.51;branch=z9hG4bK45bf.d8da62b.0;i=1. Via: SIP/2.0/TCP 158.193.139.192:49918;branch=z9hG4bK-d8754z-975d22393e6c4702-1---d8754z-;rport=49260. Max-Forwards: 69. Contact: <sip:[email protected]:49260;transport=TCP>. To: <sip:[email protected]>. From: "jojo"<sip:[email protected]>;tag=73203c66. Call-ID: N2M1MTc4MzAyNjI4ZTViZTA1NDE5MjAzZDc4ZWU3NjA.. CSeq: 2 INVITE. Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO. Content-Type: application/sdp. Supported: replaces. User-Agent: Bria Professional release 2.4 stamp 49381. Content-Length: 451. . v=0. o=- 5 2 IN IP4 158.193.139.192. s=CounterPath Bria Professional. c=IN IP4 158.193.139.192. t=0 0. m=audio 27460 RTP/AVP 107 119 100 106 0 98 8 18 101. a=fmtp:18 annexb=yes. a=fmtp:101 0-15. a=rtpmap:107 BV32/16000. a=rtpmap:119 BV32-FEC/16000. a=rtpmap:100 SPEEX/16000. a=rtpmap:106 SPEEX-FEC/16000. a=rtpmap:98 iLBC/8000. a=rtpmap:18 G729/8000. a=rtpmap:101 telephone-event/8000. a=sendrecv. a=x-rtp-session-id:8767743075B64036B830760C208977F5.
200 Ok came to the server from the client behind NAT
U 158.193.139.235:62055 -> 158.193.139.51:5060 SIP/2.0 200 OK. Via: SIP/2.0/UDP 158.193.139.51;branch=z9hG4bK45bf.d8da62b.0;i=1,SIP/2.0/TCP 158.193.139.192:49918;rport=49260;branch=z9hG4bK-d8754z-975d22393e6c4702-1---d8754z-. Record-Route: <sip:158.193.139.51;r2=on;lr=on;nat=yes>,<sip:158.193.139.51;transport=tcp;r2=on;lr=on;nat=yes>. To: <sip:[email protected]>;tag=helfk. From: "jojo" <sip:[email protected]>;tag=73203c66. Call-ID: N2M1MTc4MzAyNjI4ZTViZTA1NDE5MjAzZDc4ZWU3NjA.. CSeq: 2 INVITE. Contact: <sip:[email protected]>. Content-Type: application/sdp. Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,PRACK,REFER,NOTIFY,SUBSCRIBE,INFO,MESSAGE. Server: Twinkle/1.4.2. Supported: replaces,norefersub. Content-Length: 192. . v=0. o=twinkle 63212600 546185878 IN IP4 10.0.2.15. s=-. c=IN IP4 10.0.2.15. t=0 0. m=audio 8000 RTP/AVP 100 101. a=rtpmap:100 speex/16000. a=rtpmap:101 telephone-event/8000. a=fmtp:101 0-15.
200 OK is redirected to the calling public UA, contact is rewrited, SDP is not
T 158.193.139.51:5060 -> 158.193.139.192:49260 [AP] SIP/2.0 200 OK. Via: SIP/2.0/TCP 158.193.139.192:49918;rport=49260;branch=z9hG4bK-d8754z-975d22393e6c4702-1---d8754z-. Record-Route: <sip:158.193.139.51;r2=on;lr=on;nat=yes>,<sip:158.193.139.51;transport=tcp;r2=on;lr=on;nat=yes>. To: <sip:[email protected]>;tag=helfk. From: "jojo" <sip:[email protected]>;tag=73203c66. Call-ID: N2M1MTc4MzAyNjI4ZTViZTA1NDE5MjAzZDc4ZWU3NjA.. CSeq: 2 INVITE. Contact: <sip:[email protected]:62055>. Content-Type: application/sdp. Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,PRACK,REFER,NOTIFY,SUBSCRIBE,INFO,MESSAGE. Server: Twinkle/1.4.2. Supported: replaces,norefersub. Content-Length: 192. . v=0. o=twinkle 63212600 546185878 IN IP4 10.0.2.15. s=-. c=IN IP4 10.0.2.15. t=0 0. m=audio 8000 RTP/AVP 100 101. a=rtpmap:100 speex/16000. a=rtpmap:101 telephone-event/8000. a=fmtp:101 0-15.
The usage of the rtpproxy 1.2.1 leads to some problems, described next. I reccommend, as the working solution, to install rtpproxy 1.1.2 from the main debian repository.
Dec 3 11:29:23 pstest /usr/sbin/kamailio[5567]: ERROR: <core> [tcp_read.c:882]: ERROR: tcp_read_req: error reading
Dec 3 11:29:34 pstest kernel: [1285797.388217] rtpproxy[5529]: segfault at 0 ip 409468 sp 7fffe8208d70 error 4 in rtpproxy[400000+f000]
Go back to the standard rtpproxy debian package version 1.1.2, installed with
apt-get install rtpproxy
and change /etc/default/rtpproxy to
# Defaults for rtpproxy # The control socket. #CONTROL_SOCK="unix:/var/run/rtpproxy/rtpproxy.sock" # To listen on an UDP socket, uncomment this line: LISTEN_ADDR=158.193.139.51 CONTROL_SOCK="udp:localhost:22222" # Additional options that are passed to the daemon. EXTRA_OPTS="-l ${LISTEN_ADDR}"
Setup correctly and restart kamailio...it work now!!!!
log tutorial http://www.kamailio.org/dokuwiki/doku.php/tutorials:debug-syslog-messages