Hi Jerry, I just joined so am unsure if you are good to go now but thought I would post my config as I also have a Freeswitch environment which I have placed Kamailio in front of to act as a load-balancing proxy. I also managed to get RTPEngine proxying through it too.
Here is the config, which I have created from Daniel’s default kamailio config. I have omitted the top portions of loading the modules and their settings. My dispatcher list is just a text file. I have two groups. One for registrations and outbound calls, and one for calls inbound coming from the FreeSwitch server.
In the NATMANAGE route, I currently have RTP proxying disabled as my free switch servers have external IPs and I let them handle the rtp stream.
On Freeswitch, I made the following changes to accomodate user/pass and IPAuth reg:
Changes to the Freeswitch servers listed in the dispatcher file Edit /usr/local/freeswitch/conf/autoload_configs/acl.conf <list name="proxy" default="deny"> <node type="allow" cidr=“IP address of Kamailio/32"/> </list>
Edit /usr/local/freeswitch/conf/sip-profiles/internal-private.xml (or the sip-profile you need to edit in your instance) <param name="apply-proxy-acl" value="proxy"/> #Add this line above the one below. This tells Freeswitch to look at the X-Auth-IP header which was inserted by Kamailio.
<param name="apply-inbound-acl" value="domains"/> Then, restart freeswitch (with no active calls), service freeswitch restart # or rescan the profile / reloadxml
I am not proxying RTP, however, I can un-comment out the stanza in the NATMANAGE route to get it to work.
The biggest gotcha for me was I was trying to use fix_nated_register when handling NAT for registrations instead of:
Fix_nated_contact() or the better set_contact_alias().
Using add_path_received(); in the Dispatcher just before sending to Freeswitch ensured all traffic returned to Kamailio too.
I am unsure of the SUBSCRIBE/PRESENCE stuff for you but the route should go out via the Kamailio proxy with this.
---------------------------- # main request routing logic
request_route {
xlog("L_WARN", "--- Going to <$ru>. src_user=$fU;src_domain=$fd;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd;src_ip=$si\n"); # per request initial checks route(REQINIT);
# NAT detection route(NATDETECT);
if(ds_is_from_list("33")) { setflag(FLT_FS); #xlog("L_WARN", "This source $si is from the dispatcher list.\n"); }
# CANCEL processing if (is_method("CANCEL")) { if (t_check_trans()) { route(RELAY); } exit; }
# handle retransmissions if (!is_method("ACK")) { if(t_precheck_trans()) { t_check_trans(); exit; } t_check_trans(); }
# handle requests within SIP dialogs route(WITHINDLG);
# record routing for dialog forming requests (in case they are routed) # - remove preloaded route headers remove_hf("Route"); if (is_method("INVITE|SUBSCRIBE")) { xlog("L_WARN", "--- Going to <$ru>. src_user=$fU;src_domain=$fd;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd;src_ip=$si\n"); xlog("L_ALERT", "Marker 1\n"); record_route(); }
# account only INVITEs if (is_method("INVITE")) { setflag(FLT_ACC); # do accounting } if (isflagset(FLT_FS)) { ##t_on_reply("EXTERNAL_REPLY"); route(FROM_FS); exit; }
# handle presence related requests route(PRESENCE);
# handle registrations route(REGISTRAR);
if ($rU==$null) { # request with no Username in RURI sl_send_reply("484","Address Incomplete"); exit; }
# dispatch destinations route(DISPATCH);
return; }
route[FROM_FS] { #record_route(); #loose_route_preloaded(); route(DLGURI); route(RELAY); exit; }
route[RELAY] {
# enable additional event routes for forwarded requests # - serial forking, RTP relaying handling, a.s.o. if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) { if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH"); } if (is_method("INVITE|SUBSCRIBE|UPDATE")) { if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY"); } if (is_method("INVITE")) { if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE"); }
if (!t_relay()) { sl_reply_error(); } exit; }
#reply_route { # if(status == 403) { # xlog("L_WARN", "Forbidden from $si:$sp blah...\n"); # xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)\n"); # } #}
onreply_route[LOGRPL] { if(status == 403) { xlog("L_ALERT", "$rs response. Consider banning AVP "ipbancandidate" is $avp(ipbancandidate) "); } }
# Per SIP request initial checks route[REQINIT] { # no connect for sending replies # Enable tracing for SNGREP ##sip_trace(); ##setflag(24); # set_reply_no_connect(); # enforce symmetric signaling # - send back replies to the source address of request force_rport();
#!ifdef WITH_ANTIFLOOD # flood detection from same IP and traffic ban for a while # be sure you exclude checking trusted peers, such as pstn gateways # - local host excluded (e.g., loop to self) if(src_ip!=myself) { if($sht(ipban=>$si)!=$null) { # ip is already blocked xdbg("request from blocked IP - $rm from $fu (IP:$si:$sp)\n"); exit; } if (!pike_check_req()) { xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)\n"); $sht(ipban=>$si) = 1; exit; } } #!endif if($ua =~ "friendly|scanner|sipcli|sipvicious|VaxSIPUserAgent|pplsip|Hello\ SIP\ Automated") { # silent drop for scanners - uncomment next line if want to reply # sl_send_reply("200", "OK"); xlog("User agent is: $ua\n"); exit; }
if (!mf_process_maxfwd_header("10")) { sl_send_reply("483","Too Many Hops"); exit; }
if(is_method("OPTIONS") && uri==myself && $rU==$null) { sl_send_reply("200","Keepalive"); exit; }
if(!sanity_check("17895", "7")) { xlog("Malformed SIP message from $si:$sp\n"); exit; } }
# Handle requests within SIP dialogs route[WITHINDLG] {
if (!has_totag()) return;
# sequential request withing a dialog should # take the path determined by record-routing if (loose_route()) { xlog("L_INFO", "Routing before DLGURI\n"); route(DLGURI); if (is_method("BYE")) { setflag(FLT_ACC); # do accounting ... setflag(FLT_ACCFAILED); # ... even if the transaction fails } else if ( is_method("ACK") ) { # ACK is forwarded statelessly route(NATMANAGE); } else if ( is_method("NOTIFY") ) { # Add Record-Route for in-dialog NOTIFY as per RFC 6665. record_route(); } route(RELAY); exit; }
if (is_method("SUBSCRIBE") && uri == myself) { # in-dialog subscribe requests route(PRESENCE); exit; } if ( is_method("ACK") ) { if ( t_check_trans() ) { # no loose-route, but stateful ACK; # must be an ACK after a 487 # or e.g. 404 from upstream server route(RELAY); exit; } else { # ACK without matching transaction ... ignore and discard exit; } } sl_send_reply("404","Not here"); exit; }
# Handle SIP registrations route[REGISTRAR] { if(!is_method("REGISTER")) return; xlog("L_WARN", "--- Going to <$ru>. src_user=$fU;src_domain=$fd;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd;src_ip=$si\n"); add_path_received(); $avp(ipbancandidate) = $si; if(isflagset(FLT_NATS)) { setbflag(FLB_NATB); #!ifdef WITH_NATSIPPING # do SIP NAT pinging setbflag(FLB_NATSIPPING); #!endif } route(DISPATCH); if (!save("location")) { sl_reply_error(); } exit; }
# Presence server route route[PRESENCE] { if(!is_method("PUBLISH|SUBSCRIBE")) return;
sl_send_reply("404", "Not here"); exit; }
# Caller NAT detection route[NATDETECT] { #!ifdef WITH_NAT if (nat_uac_test("19")) { if (is_method("REGISTER")) { #fix_nated_register(); Disabled as we proxy registrations #fix_nated_contact(); set_contact_alias(); ##add_contact_alias(); #fix_nated_sdp("3"); xlog("L_ALERT", "Nat Registration nat fixed.\n"); } else { if(is_first_hop()) { set_contact_alias(); xlog("L_ALERT", "Contact NAT fixed\n"); } } setflag(FLT_NATS); xlog("L_ALERT", "FLT_NATS flag set\n"); } #!endif return; }
# RTPProxy control and signaling updates for NAT traversal route[NATMANAGE] { #!ifdef WITH_NAT if (is_request()) { if(has_totag()) { if(check_route_param("nat=yes")) { setbflag(FLB_NATB); } } } if (nat_uac_test("3")) { #fix_nated_contact(); set_contact_alias(); ##add_contact_alias(); force_rport(); } if (has_body("application/sdp") && nat_uac_test("8")) { fix_nated_sdp("11"); }
if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB))) return;
###!ifdef WITH_RTPENGINE ## xlog("RTPEngine enabled\n"); ## if(nat_uac_test("8")) { ## xlog("RTP 1\n"); ## rtpengine_manage("SIP-source-address replace-origin replace-session-connection"); ## } else { ## rtpengine_manage("replace-origin replace-session-connection"); ## } ###!else ## if(nat_uac_test("8")) { ## rtpproxy_manage("co"); ## } else { ## rtpproxy_manage("cor"); ## } ###!endif
if (is_request()) { if (!has_totag()) { if(t_is_branch_route()) { add_rr_param(";nat=yes"); xlog("Nat notation added!\n"); } } } if (is_reply()) { if(isbflagset(FLB_NATB)) { if(is_first_hop()) #fix_nated_contact(); set_contact_alias(); #add_contact_alias(); } }
if(isbflagset(FLB_NATB)) { # no connect message in a dialog involving NAT traversal if (is_request()) { if(has_totag()) { set_forward_no_connect(); } } } #!endif return; }
# URI update for dialog requests route[DLGURI] { #!ifdef WITH_NAT if(!isdsturiset()) { handle_ruri_alias(); xlog("L_INFO", "Routing in-dialog $rm from $fu to $du\n"); } #!endif return; }
# Dispatch requests route[DISPATCH] { # round robin dispatching on gateways group '1' remove_hf_re("Subject|P-.*|X-.*"); append_hf("X-Auth-IP: $si\r\n"); #add_rr_param(";nat=yes"); t_on_reply("LOGRPL"); if(!ds_select_dst("1", "0")) { send_reply("404", "No destination"); exit; } #xdbg("--- SCRIPT: going to <$ru> via <$du> (attrs: $xavp(_dsdst_=>attrs))\n"); xlog("L_WARN", "--- Going to <$ru>. src_user=$fU;src_domain=$fd;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd;src_ip=$si; $RAi; $Ri;\n"); t_on_failure("RTF_DISPATCH"); route(RELAY); }
# Try next destionations in failure route failure_route[RTF_DISPATCH] { if (t_is_canceled()) { exit; } # next DST - only for 500 or local timeout if (t_check_status("500") or (t_branch_timeout() and !t_branch_replied())) { if(ds_next_dst()) { xdbg("--- SCRIPT: retrying to <$ru> via <$du> (attrs: $xavp(_dsdst_=>attrs))\n"); t_on_failure("RTF_DISPATCH"); route(RELAY); exit; } } }
# Manage outgoing branches branch_route[MANAGE_BRANCH] { xdbg("new branch [$T_branch_idx] to $ru\n"); xlog("L_ALERT", "Marker 20\n"); route(NATMANAGE); return; }
# Manage incoming replies reply_route { if(!sanity_check("17604", "6")) { xlog("Malformed SIP response from $si:$sp\n"); drop; } return; }
# Manage incoming replies in transaction context onreply_route[MANAGE_REPLY] { xdbg("incoming reply\n"); xlog("L_ALERT", "Marker 21\n"); if(status=~"[12][0-9][0-9]") { route(NATMANAGE); } # if (has_body("application/sdp")) { # rtpengine_manage(); # } return; }
# Manage failure routing cases failure_route[MANAGE_FAILURE] { xlog("L_ALERT", "Marker 23\n"); route(NATMANAGE);
if (t_is_canceled()) exit;
#!ifdef WITH_BLOCK3XX # block call redirect based on 3xx replies. if (t_check_status("3[0-9][0-9]")) { t_reply("404","Not found"); exit; } #!endif
#!ifdef WITH_BLOCK401407 # block call redirect based on 401, 407 replies. if (t_check_status("401|407")) { t_reply("404","Not found"); exit; } #!endif
#!ifdef WITH_VOICEMAIL # serial forking # - route to voicemail on busy or no answer (timeout) if (t_check_status("486|408")) { $du = $null; route(TOVOICEMAIL); exit; } #!endif return; }