Here is my situation:
UAC1----\ /-------PSTN \ SER----ASTERISK/ / \ UAC2----/ \ ----- INTERNET
SER listening on 192.168.1.100 (towards the internal LAN -> UAC1 and UAC2), and on 88.148.87.236 towards the internet ; SER doing NAT between the internal and external networks; SER serving as a registrar; RTP Proxy installed on the SER machine, and started with rtpproxy -l 192.168.1.100/88.148.87.236
problem is NATed UAC1 and UAC2 don't get any audio when calling to a public endpoint, but can successfully call each other.
when the call is established, I am getting the following errors in the onreply_route:
6(1742) ERROR: extract_body: message body has lenght zero 6(1742) ERROR: force_rtp_proxy2: can't extract body from the message
are there any parameters that should be handed to force_rtp_proxy()? i noticed it has been called with II/EI/IE in the application layer gateway example - alg.cfg marking Internal/External locations. in that example. however both networks are RFC1918, i.e. no nathelper is necessary.
below is my ser.cfg. please excuse the excessive logging, but i'm trying to figure out how it all works...
# # $Id: ser.cfg,v 1.21.4.1 2003/11/10 15:35:15 andrei Exp $ # # simple quick-start config script #
# ----------- global configuration parameters ------------------------
debug=3 # debug level (cmd line: -dddddddddd) fork=yes log_stderror=yes # (cmd line: -E)
alias=mertel.net alias=88.148.87.236 alias=192.168.1.100
check_via=no # (cmd. line: -v) syn_branch=yes sip_warning=yes dns=no # (cmd. line: -r) rev_dns=no # (cmd. line: -R) port=5060 children=4 fifo="/tmp/ser_fifo" server_signature=yes reply_to_via=no
# ------------------ module loading ----------------------------------
# Uncomment this if you want to use SQL database loadmodule "/usr/local/lib/ser/modules/mysql.so" loadmodule "/usr/local/lib/ser/modules/nathelper.so" loadmodule "/usr/local/lib/ser/modules/textops.so" loadmodule "/usr/local/lib/ser/modules/sl.so" loadmodule "/usr/local/lib/ser/modules/tm.so" loadmodule "/usr/local/lib/ser/modules/rr.so" loadmodule "/usr/local/lib/ser/modules/maxfwd.so" loadmodule "/usr/local/lib/ser/modules/usrloc.so" loadmodule "/usr/local/lib/ser/modules/registrar.so" loadmodule "/usr/local/lib/ser/modules/exec.so" # Uncomment this if you want digest authentication # mysql.so must be loaded ! loadmodule "/usr/local/lib/ser/modules/auth.so" loadmodule "/usr/local/lib/ser/modules/auth_db.so" loadmodule "/usr/local/lib/ser/modules/acc.so" loadmodule "/usr/local/lib/ser/modules/uri.so" # ----------------- setting module-specific parameters --------------- modparam("tm", "fr_timer", 12) modparam("tm", "fr_inv_timer", 24) modparam("usrloc", "db_mode", 2)
modparam("auth_db", "calculate_ha1", yes) modparam("auth_db", "password_column", "password")
modparam("rr", "enable_full_lr", 1)
modparam("acc", "db_flag", 2) modparam("acc", "db_missed_flag", 3)
modparam("registrar", "nat_flag", 6)
modparam("nathelper", "natping_interval", 30) modparam("nathelper", "ping_nated_only", 1)
# ------------------------- request routing logic -------------------
route { log(1, "--------\n"); log(1, "LOG:Entering main route loop\n");
#initial sanity checks if (!mf_process_maxfwd_header("10")) { log(1, "LOG: Too many hops\n"); sl_send_reply("483", "Too many hops"); break; };
if (msg:len > max_len) { sl_send_reply("513", "Message too big"); };
# test if the client is nated if(nat_uac_test("3")) { log(1, "LOG:NAT detected\n"); if(method=="REGISTER" || ! search("^Record-Route:")) { log(1, "LOG: Received REGISTER request from a NATed client, calling fix_nated_contact()... \n"); if(!fix_nated_contact()) { log(1, "LOG: fix_nated_contact() FAILED!\n"); } else { log(1, "LOG: fix_nated_contact() successful.\n"); }; if(method=="INVITE") { log(1, "LOG: Received INVITE request, calling fix_nated_sdp()...\n"); if(!fix_nated_sdp("1")) { log(1, "LOG: fix_nated_sdp() FAILED!\n"); } else { log(1, "LOG: fix_nated_sdp() successful.\n"); }; }; log(1, "LOG: Calling force_rport()...\n"); if(!force_rport()) { log(1, "LOG: force_rport() FAILED !\n"); } else { log(1, "LOG: force_rport() successful.\n"); }; log(1, "LOG: calling setflag(6)...\n"); if(!setflag(6)) { log(1, "LOG: setting flag 6 FAILED!\n"); } else { log(1, "LOG: Flag 6 set successfully.\n"); }; append_hf("P-hint: fixed NAT contact for request\r\n"); }; # close if(method=="REGISTER");
}; #close if(nat_uac_test)
if (method=="REGISTER") log(1, "LOG: REGISTER msg received.\n"); if (method=="INVITE") log(1, "LOG: INVITE msg received.\n"); if (method=="ACK") log(1, "LOG: ACK msg received.\n"); if (method=="BYE") log(1, "LOG: INVITE msg received.\n"); if (method=="CANCEL") log(1, "LOG: CANCEL msg received.\n"); if (method=="SUBSCRIBE") log(1, "LOG: SUBSCRIBE msg received.\n"); if (method=="NOTIFY") log(1, "LOG: NOTIFY msg received.\n"); if (method=="OPTIONS") log(1, "LOG: OPTIONS msg received.\n"); if (method=="INFO") log(1, "LOG: INFO msg received.\n"); if (method=="MESSAGE") log(1, "LOG: MESSAGE msg received.\n"); if (method=="REFER") log(1, "LOG: REFER msg received.\n");
if(!method=="REGISTER") { log(1, "LOG: recording route...\n"); record_route(); };
#if processing a loose route() if (loose_route()){ log(1, "Processing loose route.\n"); append_hf("P-hint: rr-enforced"); t_relay(); break; };
# ROUTING TOWARDS ASTERISK if ((uri=~"sip:033[0-9]{3,20}@.*") | (uri=~"sip:02[0-9]{3,20}@.*") | (uri=~"sip:[56][0]{2}@.*") | uri=~"sip:08314[0-9]{4}@" | uri=~"sip:12[34]@" | uri=~"sip:32[0]{3}[1]@" ) { log(1, "LOG: Destination is Asterisk - switching to route[3]\n"); route(3); # - handles routing to Asterisk GW break; };
if (!(uri==myself)) { log(1, "LOG: Detected an outbound destination (uri!=myself) - switching to route[2]\n"); append_hf("P-hint: outbound"); route(2); # - handles routing to outbound destinations, i.e. not local break; };
if(uri==myself) { log(1, "LOG: uri==myself \n"); if(method=="REGISTER") { log(1, "LOG: Analyzing REGISTER request\n"); if(!www_authorize("mertel.net", "subscriber")) { log(1, "LOG: User not authorized - sending www_challenge()...\n"); www_challenge("mertel.net","0"); #this reenters route block break; }; if(!is_user("replicator") & !check_to()) { log(1, "LOG: Unregistered user registration attempt\n"); sl_send_reply("403", "Only registered users are allowed"); break; }; log(1, "LOG: User is authorized, saving location...\n"); if(!save("location")) { log(1, "LOG: !!!!! save location error on registration !!!!!"); sl_reply_error(); } else { log(1, "LOG: User location saved successfully.\n"); }; break; }; # - closes if(method=="REGISTER")
#lookup("aliases");
# mostly offline or non-existent users if(!lookup("location")) { log(1, "LOG: Sending 404 not found ! \n"); sl_send_reply("404", "Not found"); break; };
}; #closes if(uri==myself)
append_hf("P-hint: usrloc aplied"); route(2);
} /* end of initial routing logic */
route[2] {
log(1, "LOG: Entering route[2] now...\n");
# check for RFC1918 ip addresses # -- NATHELPER -- if(uri=~"[@:](192.168. 10. 172.(1[6-9]|2[0-9]|3[0-1]).)" && !search("^Route:")) { sl_send_reply("479", "We do NOT forward to RFC 1918 IP addresses\n"); break; };
#check if the NAT Flag is set if (isflagset(6)) { log(1, "LOG: flag 6 set => One of the sides is NATed -> force_rtp_proxy()\n"); if(!force_rtp_proxy()) { log(1, "LOG: force_rtp_prpoxy FAILED!\n"); } else { log(1, "LOG: force_rtp_proxy() succeeded!\n"); }; };
log(1, "LOG:setting up reply processing\n"); t_on_reply("2");
# outbound requests are allowed only for registered mertel.net users if (!(src_ip==88.148.87.236) & !(proxy_authorize("mertel.net", "subscriber"))) {
# ACK and CANCEL have no security mechanisms so they are just noted if (method=="ACK" | method=="BYE") { log(1, "LOG: failed outbound authentication for ACK granted\n"); } else if (method=="CANCEL") { log(1, "LOG: failed outbound authentication for CANCEL granted\n"); } else if ( src_ip==88.148.87.237 ) { log(1, "LOG: Incoming FROM ASTERISK TO SIP\n"); } else { proxy_challenge("mertel.net", "0"); break; }; };
# to maintain credibility of our proxy, we check From in INVITEs if (!src_ip==88.148.87.236 & method=="INVITE" & !check_from()) { log(1, "LOG: Spoofed from attempt\n"); sl_send_reply("403", "Use From=id next time"); break; };
log(1, "LOG: relaying message...\n");
if (!t_relay()) { log(1, "LOG: t_relay error occured ! \n"); sl_reply_error(); }; }
onreply_route[2] {
log(1, "LOG: entered onreply_route[2] now... \n");
if(isflagset(6) && status =~"(183)|2[0-9][0-9]") { log(1, "LOG: TRansaction was sent to a NATed client --> fix_nated_contact() and force_rtp_proxy().\n"); if(!fix_nated_contact()) { log(1, "LOG: fix_nated_contact() FAILED!\n"); } else { log(1, "LOG: fix_nated_contact() succeded.\n"); }; if(!force_rtp_proxy()) { log(1, "LOG: force_rtp_proxy() FAILED!\n"); } else { log(1, "LOG: force_rtp_proxy() succeded.\n"); }; append_hf("P-hint: fixed NAT contact for response\r\n"); } else if (nat_uac_test("1")) { log(1, "LOG: Uncaught NAT. => fix_nated_contact()\n"); if(!fix_nated_contact()) { log(1, "LOG: fix_nated_contact() FAILED!\n"); } else { log(1, "LOG: fix_nated_contact() succeded.\n"); }; };
if((status=~"100")) { log(1, "LOG: received status 100\n"); };
if((status=~"180")) { log(1, "LOG: received status 180\n"); };
if((status=~"202")) { log(1, "LOG: received status 202\n"); }; }
#route[3] routes calls to the gateway route[3] {
log(1, "LOG: Entered route[3] now...\n"); # all calls through the gateway must be record routed to assure # acl acceptance on the gateway #record_route(); # first the caller needs to be authenticated if (!(src_ip==88.148.87.236 | method==ACK | method=="CANCEL" | method=="BYE")) { if ( ! src_ip==88.148.87.237 ) { log(1, "LOG: Inbound call FROM ASTERISK !!!\n"); if (!proxy_authorize("mertel.net", "subscriber")) { proxy_challenge( "mertel.net","0"); break; } else if (method=="INVITE" & !check_from()) { log(1, "LOG: Spoofed from attempt\n"); sl_send_reply("403", "Use From=id next time"); break; }; }; }; rewritehostport("88.148.87.237:5060"); append_hf("P-hint: GATEWAY\r\n"); log(1, "LOG: Relaying to Gateway\n"); if (!t_relay()) { sl_reply_error(); break; }; }