Hi all
I've set up a kamailio server on a public IP address to serve public clients.
- The clients REGISTER over a mix of TCP and TLS, so kamailio has
listeners on the same IP address: port 5060 for UDP/TCP and port 5061
for TLS.
- Some clients REGISTER from the same public IP address, behind the same NAT.
- Sometimes, the client-side NAT can use the same client-side IP
address and port for two concurrent connections - one TCP and one TLS
- which is normal because the server-side port is different (they're
different 5-tuples).
- Now when a request comes to kamailio, to be routed to a client, the
the t_relay_to_tls() function sometimes can relay the request over a
TCP connection instead of a TLS connection.
I've enabled tcp_connection_match=1. This is helpful, but it doesn't
completely resolve the problem. It helps when both connections (TCP
and TLS) are open, because the TLS connection will always be used for
TLS requests. However, when there's no TLS connection open, kamailio
will erroneously use the TCP connection.
Note that this setup depends on TCP/TLS connections being made from
the client to the server, not the other way around.
I've made a cut-down version of this setup to demonstrate the problem.
- Client: 11.15.32.1
- Server: 11.15.32.11
- version: kamailio 5.9.0-dev0 (x86_64/linux)
#################################################################
#!KAMAILIO
enable_tls=yes
listen=tls:11.15.32.11:5061
listen=tcp:11.15.32.11:5060
listen=udp:11.15.32.11:5060
loadmodule "tm"
loadmodule "tls"
loadmodule "pv"
loadmodule "rr"
fork=yes
log_facility=LOG_LOCAL0
log_stderror=no
children=2
debug=3
tcp_connection_match=1
modparam("tls", "low_mem_threshold1", -1)
modparam("tls", "low_mem_threshold2", -1)
modparam("tls", "certificate", "/usr/local/etc/kamailio/certs/chain")
modparam("tls", "private_key", "/usr/local/etc/kamailio/certs/key")
request_route {
loose_route();
$fs="tls:11.15.32.11:5061";
t_relay_to_tls();
}
#################################################################
This is a BYE message to be sent from internally in the network.
###########################
BYE sip:user3@11.15.32.1:33333;transport=tls SIP/2.0
Via: SIP/2.0/UDP 0.0.0.0:11111;rport;branch=z9hG4bK-d8754z-cc2c63344f5218d3-1
Route: <sip:11.15.32.11:5060;transport=tcp;r2=on;lr;ftag=ZUrDU2m4Z9Zam>
Route: <sip:11.15.32.11:5061;transport=tls;r2=on;lr;ftag=ZUrDU2m4Z9Zam>
f: <sip:user1@server>;tag=ZUrDU2m4Z9Zam
t: <sip:user3@server>;tag=gK0ea97395
i:sdfg8we790t874ujk
CSeq: 102 BYE
Content-Length: 0
###########################
When I send that to kamailio over UDP, kamailio relays it over a TCP
connection, as seen with socat here (socat runs on the machine with
address 11.15.32.1).
###########################
$ socat - TCP:11.15.32.11:5060,bind=:33333
BYE sip:user3@11.15.32.1:33333;transport=tls SIP/2.0
Via: SIP/2.0/TLS
11.15.32.11:5061;branch=z9hG4bKd2bf.137932ff9a937cde941fd1790db040c9.0
Via: SIP/2.0/UDP
0.0.0.0:11111;received=11.15.32.11;rport=11111;branch=z9hG4bK-d8754z-cc2c63344f5218d3-1
f: <sip:user1@server>;tag=ZUrDU2m4Z9Zam
t: <sip:user3@server>;tag=gK0ea97395
i:sdfg8we790t874ujk
CSeq: 102 BYE
Content-Length: 0
###########################
Note that
- the RURI has transport=tls in it,
- kamailio is forcing the TLS socket,
- kamailio is using the t_relay_to_tls function,
- the Route header field tells that TLS should be used, and
- the Via header field shows that kamailio tried to send this over TLS, but
- the BYE was sent over unencrypted TCP.
If I use this socat command instead, then I can receive the BYE,
showing that kamailio is able to use TLS if there's a connection
available.
- socat - OPENSSL:11.15.32.11:5061,bind=:33333,verify=no
I can't find any setting to control this, so it looks to me like a
kamailio bug. At that, I see this as a security flaw, because the SIP
traffic should always be encrypted but now is leaked.
Can anyone help?
James
Hi,
I use KEMI/Lua. I have simple lua class:
myclass = {}
myclass.event = function()
KSR.xlog.xinfo("Event working...\n")
end
In kamailio.conf have:
modparam("xhttp", "event_callback", "myclass.event")
In debug log have:
Mar 12 13:21:30 kamailio DEBUG: app_lua [app_lua_api.c:549]: sr_lua_reload_script(): No need to reload [/etc/kamailio/donjon.lua] is version 0
Mar 12 13:21:30 kamailio DEBUG: app_lua [app_lua_api.c:733]: app_lua_run_ex(): executing Lua function: [[myclass.event]]
Mar 12 13:21:30 kamailio DEBUG: app_lua [app_lua_api.c:735]: app_lua_run_ex(): lua top index is: 40
Mar 12 13:21:30 kamailio DEBUG: app_lua [app_lua_mod.c:164]: sr_kemi_config_engine_lua(): execution of route type 513 with name [myclass.event] returned 1
The problem is that the event function in the myclasses class is not called.
Is there any other way or syntax to do this? Of course, if I define a function without a class, it works.
Thanks
Michal
My SIP proxy didn't start with Kamailio 5.8 using the same config that
starts OK with 5.7. The error is:
2024-03-11T06:56:06.457107+02:00 lohi /usr/bin/sip-proxy[2358954]: DEBUG: acc [acc_mod.c:362]: parse_failed_filter(): failed_filter 0 = 407
2024-03-11T06:56:06.457265+02:00 lohi /usr/bin/sip-proxy[2358954]: ERROR: acc [acc_mod.c:369]: parse_failed_filter(): response code is not followed by comma or end of string
2024-03-11T06:56:06.457436+02:00 lohi /usr/bin/sip-proxy[2358954]: ERROR: acc [acc_mod.c:439]: mod_init(): failed to parse failed_filter param
The relevant params are:
modparam("acc", "failed_transaction_flag", 8)
modparam("acc", "failed_filter", "407")
I didn't find any difference in acc_mod.c source code between 5.7 and
5.8 and parse_failed_filter function looked OK.
Then I added a debug statement in the beginning of parse_failed_filter
function:
LM_DBG("parsing failed_filter %s\n", s);
and got to syslog:
cc_mod.c:341]: parse_failed_filter(): parsing failed_filter 407rmissions|pua|rtpengine)$
That explains the parse_failed_filter error, but where does that bogus
param value come from?
Before acc params I have:
modparam("auth_db|dialplan|domain|htable|lcr|msilo|mtree|permissions|pua|rtpengine", "db_url", "mysql://xxxx/sip_proxy")
modparam("registrar|nathelper", "received_avp", "$avp(received_uri)")
So it from there, but why? Is there a bug somewhere or is my SIP proxy
running out of memory or something? Before the above error messages,
there are no other error messages.
-- Juha
Hello Kamailians!
Before I start going down this path - anyone that has written a Kamailio Yocto layer and want to share either layer or experience or both?
For those that doesn’t know: Yocto is a toolkit for building your own Linux distros for embedded systems.
/O
Hi everyone
I have a small question:
i want to set up a basic SIP Redirect Server
so I install Kamailio v5.3
and comment default request route and set simple
request_route {
rewritehostport("1.2.3.4");
sl_send_reply("302", "Moved Temporarily");
}
but for some reason, Kamailio does not care about the port and sends a
reply to 5060
[image: image.png]
i also tried to delete rewritehostport
but it only deletes Contact: from the reply
but reply itself is still sent to 5060 port
[image: image.png]
--
*Antony*
satskiy.a(a)gmail.com
+380669197533
+48727830247
Kamailio 5.8 build generates on my Debian 12 the following warning:
core/mem/q_malloc.c:996:14: warning: 'qm_strnstr' defined but not used [-Wunused-function]
996 | static void *qm_strnstr(const void *b1, int l1, const void *b2, int l2)
| ^~~~~~~~~~
Perhaps the definition of the function should be #ifdef'ed by
DBG_QM_MALLOC.
-- Juha
I've been tasked to use LD_PRELOAD to log SSL keys for TLS connections
using a Diffie-Hellman cipher. The first attempt did not work, so I wanted
to sanity check whether Kamailio's TLS support is built in such a way that
would defeat LD_PRELOAD.
The instructions from the vendor are to update /etc/init.d/kamailio like
this:
env SSLKEYLOG_UDP='127.0.0.1:1234'
LD_PRELOAD="/usr/local/src/voipmonitor-git/tools/ssl_keylogger/sslkeylog.so
/usr/lib/x86_64-linux-gnu/libssl.so.3" \
start-stop-daemon --start --quiet --pidfile $PIDFILE \
--exec $DAEMON -- $OPTIONS || log_failure_msg " already
running"
Is there anything special in Kamailio (5.7.3 on Debian 12) that would
prevent this from working? Not necessarily something to defeat a keylogger,
but maybe the way tls.so gets loaded?
The only discrepancy I've noticed is the vendor docs refer to libssl.so.3
not libssl.so.1, but the vendor said that should be OK.
I'd love to hear from someone already using VoIPmonitor with Diffie-Hellman
ciphers and Kamailio.
Hi kamailio community,
I have an issue with a Kamailio 5.7. It's listening both in TCP and
UDP. In my scenario requests arrive from devices on TCP, but I want to
forward to the next hops on UDP. I am avoiding using any type of DNS
resolution; since I am always forwarding to predefined next hops I am
using the dispatcher module (defined with the IP addresses and
transport=udp) or I wrote config files using t_relay_to_udp or
t_relay_to with a udp: followed by IP address. I never set up FQDNS
only IP addresses and in all of them I explicitly mention UDP.
In all of these scenarios I have tried Kamailio insists in trying to use
TCP with the next hop and failing because the next_hop is only UDP. I
guess because the message arrived using TCP Kamilio does that but I find
the behavior very confusing.
I nailed down that in my situation its the tm module function
prepare_new_uac (in file src/modules/tm/t_fwd.c line 119) being the one
that missbehaves. The documentation of the function says literraly :
"* t->uac[branch].request.dst will be filled if next_hop !=0 with the result
* of the DNS resolution (next_hop, fproto and fsocket).
* If next_hop is 0 all the dst members except the send_flags are read-only
* (send_flags it's updated) and are supposed to be pre-filled."
I found out that even when next_hop is 0 the function changes the
t->uac[branch].request.dst proto, socket etc. its there that the
kamailio takes the wrong decision, until that function is called within
add_auc, the destination proto or the fproto etc is always 1 (UDP)
which is what I am trying to force from the config file or the
dispatcher definition (I tried both ways). But after calling that
function then it comes as a 2 (TCP)
The problematic function is a monster of 500 lines and I would like to
avoid having to understand it. Since I think the scenario is not so
unusual I just want to ask if maybe I am missing something that I should
do to avoid the Kamailio to select TCP and in order to have the tm
module respecting my preference for UDP (either with dispatcher module
and the transport param or with t_relay_to or t_relay_to_udp I don't
care the way).
Any hints are welcome.
Best regards
alberto
Hi all!
got a weird behavior that I cannot understand the reason for...
In our LAB environment, we have 2 Asterisk instances (version 13.38.3
and chan_sip) and 1 Kamailio 5.7 in between.
All servers are in the same network, so, there is no NAT involved. No
RTPEngine either.
Network is 10.20.0.0/24 and Asterisk #1 has IP .1 Asterisk #2 has IP
.3 and Kamailio has IP .5
The Asterisk servers are used only for testing, nothing serious.
However, Kamailio is setup to use RTJson requesting routes to a
Routing Server on the same network. And it works fine.
Both Asterisk servers have the same dialplan, which only Answers the
call and plays MOH on both ends so that RTP audio streams both ways.
When making a call on Asterisk Server #1 via command line to go
directly to Asterisk Server #2 without using Kamailio (CLI> channel
originate SIP/123(a)10.20.0.3 application MusicOnHold() ) the Asterisk
#2 receives the call, answers and plays MOH too and I can see RTP
streams coming from both ends correctly.
However, if I use Kamailio to proxy the call generated from Asterisk
#1 to Asterisk #2, using similar command line instruction (CLI>
channel originate SIP/123(a)10.20.0.5 application MusicOnHold() ), the
call is indeed received on Kamailio who then sends it to Asterisk #2,
who answers the call and plays MOH, *but* despite the audio stream
being sent to Asterisk #1 it is never received, however audio from
Asterisk #1 is received by Asterisk #2, which configures a typical One
Way Audio issue due to NAT.
This is where it gets strange, because there is no NAT, SDP on INVITE
and SIP 200 messages seem OK, as far as I understand it.
Also, Asterisk servers have SIP configuration with directmedia enabled
and NAT disabled to make sure that media is direct. But I have also
tried with directmedia disabled and NAT enabled and get identical
results.
I am most probably missing some tiny detail, but I have no clue....
and I bet it is simple and stupid....
Could another pair of eyes help me with this? What is wrong? Do I
really need RTPEngine even when the network has no NAT? I am sure it
would work that way, but it doesn't make sense...
Here are some screenshots:
Call Scenario #1 - direct call from Asterisk #1 to Asterisk #2 without
Kamailio in between:
Invite from Asterisk #1 to Asterisk #2 with direct media between both ends:
https://drive.google.com/file/d/1eLjT3nr_Rc-UBaf4QhIgZ95bjETOVvxo/view?usp=…
Replies from Asterisk #2 to Asterisk #1 with direct media between both ends:
https://drive.google.com/file/d/11lLcB-V8rWGSrVqWiit-q9WX2FfqB6BZ/view?usp=…
Call Scenario #2 - call from Asterisk #1 using Kamailio to relay call
to Asterisk #2, with one way audio
Invite from Asterisk #1 to Asterisk #2 via Kamailio with SDP details:
https://drive.google.com/file/d/1Cp9xrGcwNmQ9Ks36N_oD1Dj7lxfu-tbH/view?usp=…
Invite from Kamailio relayed to Asterisk #2 with SDP details from
Asterisk #1 identical to above:
https://drive.google.com/file/d/1mi3FCNjM3luXfENEp-0088XLgcyfXRK6/view?usp=…
Reply from Asterisk #2 to Kamailio with SDP details:
https://drive.google.com/file/d/1TpMGe2tvpX_5SIpSbm2b3Zro9EuYwcO-/view?usp=…
Reply from Kamailio to Asterisk #2 with SDP details from Asterisk #2
identical to above:
https://drive.google.com/file/d/12jq5APfFwVVPc0vJ3RkcXyN1hBE51fnQ/view?usp=…
As we can see, SDP details seem OK, but if I check call flow on
Asterisk #1, I can only find 1 RTP channel with audio coming from
Asterisk #2
https://drive.google.com/file/d/1iEfvkylZVbthHM5kxkurWh-GAYCYLytl/view?usp=…
and the same on Asterisk #2 :
https://drive.google.com/file/d/12rvf9Lrwp-MNZvGCwlXEEBsBRmfcinph/view?usp=…
My Kamailio.cfg is as follows:
#!KAMAILIO
#
# config file for SIPProxy
# - load balancing of VoIP calls
# - no TPC listening
#
# Kamailio (OpenSER) SIP Server v3.2
# - web: http://www.kamailio.org
# - git: http://sip-router.org
#
#
# Refer to the Core CookBook at http://www.kamailio.org/dokuwiki/doku.php
# for an explanation of possible statements, functions and parameters.
#
# Several features can be enabled using '#!define WITH_FEATURE' directives:
#
# *** To run in debug mode:
# - define WITH_DEBUG
#
#!define WITH_DEBUG
###!define WITH_NAT
#!define WITH_PSTN
/* enables Accounting Log functions */
#!define FLT_ACC 1
/* enable Accounting of missed or failed calls */
#!define FLT_ACCMISSED 2
#!define FLT_ACCFAILED 3
/* defines DB connection string */
#!ifndef DBURL
#!define DBURL "mysql://kamailio:kamailio@10.20.0.1:3306/kamailio"
#!endif
# - the value for 'use_domain' parameters
#!define MULTIDOMAIN 1
####### Global Parameters #########
#!ifdef WITH_DEBUG
debug=4
log_stderror=no
#!else
debug=2
log_stderror=no
#!endif
#!define FLT_DISPATCH_SETID 1
#!define FLT_FS 10
#!define FLT_NATS 5
#!define FLB_NATB 6
#!define FLB_NATSIPPING 7
#!define FLT_SRC_ALLOWED 8
#!define FLT_DST_INTERNAL_IP 9
#!define FLT_SRC_INTERNAL_IP 10
#!substdef "!INTERNAL_IP_NET!10.20.0.0/24!g"
#!substdef "!INTERNAL_IP_ADDR!10.20.0.2!g"
#!substdef "!EXTERNAL_IP_ADDR!10.20.0.2!g"
#!ifndef HTTP_ASYNC_CLIENT_WORKERS
#!define HTTP_ASYNC_CLIENT_WORKERS 8
#!endif
/* add API http timeout */
#!define HTTP_API_TIMEOUT 5000
#!define HTTP_API_ROUTING_ENDPOINT "http://10.246.212.40:7778/get_route"
/* DMQ SIP message sharing */
#!define DMQ_PORT 5062
#!define DMQ_LISTEN "sip:10.20.0.2:5062"
#!define DMQ_SERVER_ADDRESS "sip:10.20.0.2:5062"
#!define DMQ_NOTIFICATION_ADDRESS "sip:10.20.0.4:5062"
memdbg=5
memlog=5
log_facility=LOG_LOCAL0
log_prefix="{$mt $hdr(CSeq) $ci} "
fork=yes
children=8
/* comment the next line to enable TCP - all trunks are UDP only */
disable_tcp=yes
/* uncomment the next line to disable the auto discovery of local aliases
based on revers DNS on IPs (default on) */
auto_aliases=no
port=5060
/* uncomment and configure the following line if you want Kamailio to
bind on a specific interface/port/proto (default bind on all available) */
listen=udp:10.20.0.5:5060 advertise 10.20.0.5:5060
listen=tcp:10.20.0.5:5060 advertise 10.20.0.5:5060
listen=udp:10.20.0.2:5062
advertised_address="10.20.0.5";
sip_warning=no;
use_dns_failover = on;
####### Modules Section ########
#set module path
mpath="/usr/local/lib64/kamailio/modules/"
loadmodule "db_mysql.so"
loadmodule "jsonrpcs.so"
loadmodule "kex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "textops.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "acc.so"
loadmodule "usrloc.so"
loadmodule "nathelper.so"
#loadmodule "rtimer.so"
#loadmodule "sqlops.so"
# --- CPS Limiter
# --- end of CPS Limiter
loadmodule "ipops.so"
loadmodule "textopsx.so"
loadmodule "sdpops.so"
loadmodule "http_async_client.so"
loadmodule "rtjson.so"
loadmodule "jansson.so"
loadmodule "dmq.so"
loadmodule "dmq_usrloc.so"
loadmodule "htable.so"
loadmodule "dialog.so"
#!ifdef WITH_DEBUG
loadmodule "debugger.so"
#!endif
#!ifdef WITH_DEBUG
# ----- debugger params -----
modparam("debugger", "log_level_name", "exec")
#!endif
# ----------------- setting module-specific parameters ---------------
# ----- jsonrpcs params -----
modparam("jsonrpcs", "fifo_name", "/var/run/kamailio/kamailio_rpc.fifo")
modparam("jsonrpcs", "pretty_format", 1)
# ----- rr params -----
modparam("jsonrpcs", "fifo_name", "/var/run/kamailio/kamailio_rpc.fifo")
modparam("jsonrpcs", "pretty_format", 1)
# ----- 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)
# ----- acc params -----
modparam("acc", "failed_transaction_flag", 3)
modparam("acc",
"log_extra","src_user=$fU;src_domain=$fd;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd;src_ip=$si")
# ----- acc params -----
/* what special events should be accounted ? */
modparam("acc", "early_media", 0)
modparam("acc", "report_ack", 0)
modparam("acc", "report_cancels", 0)
/* by default we 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", "log_flag", FLT_ACC)
modparam("acc", "log_missed_flag", FLT_ACCMISSED)
modparam("acc",
"log_extra","src_user=$fU;src_domain=$fd;src_ip=$si;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
modparam("acc", "failed_transaction_flag", FLT_ACCFAILED)
/* enhanced DB accounting */
modparam("acc", "db_flag", FLT_ACC)
modparam("acc", "db_missed_flag", FLT_ACCMISSED)
modparam("acc", "db_url", DBURL)
modparam("acc",
"db_extra","src_user=$fU;src_domain=$fd;src_ip=$si;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
//;calltype=$avp(calltype)")
# ----- tm params -----
# ----- the TM module enables stateful processing of SIP requests
modparam("tm", "fr_timer", 5000)
modparam("tm", "fr_inv_timer", 60000)
modparam("tm", "remap_503_500", 0)
# ----- usrloc params -----
/* enable DB persistency for location entries */
modparam("usrloc", "db_url", DBURL)
modparam("usrloc", "db_mode", 2)
modparam("usrloc", "use_domain", MULTIDOMAIN)
# params needed for NAT traversal in other modules
modparam("usrloc", "nat_bflag", FLB_NATB)
# ----- nathelper params -----
modparam("nathelper", "received_avp", "$avp(s:rcv)")
modparam("nathelper", "natping_interval", 30)
modparam("nathelper", "ping_nated_only", 1)
modparam("nathelper", "sipping_bflag", FLB_NATSIPPING)
modparam("nathelper", "sipping_from", "sip:ping@kamailio.org")
#modparam("rtimer", "timer", "name=cdr;interval=300;mode=1;")
#modparam("rtimer", "exec", "timer=cdr;route=CDRS")
#modparam("sqlops", "sqlcon",
"ca=>mysql://kamailio:kamailiorw@10.19.139.113:3306/kamailio")
#modparam("dmq", "server_socket", DMQ_SERVER_SOCKET )
modparam("dmq", "server_address", DMQ_SERVER_ADDRESS )
modparam("dmq", "notification_address", DMQ_NOTIFICATION_ADDRESS )
modparam("dmq", "multi_notify", 1)
modparam("dmq", "num_workers", 4)
modparam("dmq", "ping_interval", 60)
modparam("dmq_usrloc", "enable", 1)
# -- CPS Limiter
modparam("htable", "htable", "rhs=>size=32;initval=0;autoexpire=10;")
modparam("htable", "htable", "rhm=>size=32;initval=0;autoexpire=120;")
modparam("htable", "enable_dmq", 1)
modparam("htable", "dmq_init_sync", 1)
modparam("dialog", "profiles_with_value", "concurrent_calls")
modparam("dialog", "enable_dmq", 1)
# ----- http_async_client params -----
modparam("http_async_client", "workers", HTTP_ASYNC_CLIENT_WORKERS)
modparam("http_async_client", "connection_timeout", 2000)
####### Routing Logic ########
# main request routing logic
route {
if (is_method("KDMQ") && $Rp == 5062)
{
dmq_handle_message();
}
xlog("L_INFO"," ********** Route START ***********");
# log the basic info regarding this call
xlog("L_INFO","start|\n");
xlog("L_INFO","===================================================\n");
xlog("L_INFO","New SIP message $rm with call-ID $ci \n");
xlog("L_INFO","---------------------------------------------------\n");
xlog("L_INFO"," received $pr request $rm $ou\n");
xlog("L_INFO"," source $si:$sp\n");
xlog("L_INFO"," from $fu\n");
xlog("L_INFO"," to $tu\n");
xlog("L_INFO","---------------------------------------------------\n");
xlog("L_INFO","---------------------------------------------------\n");
# OPTIONS requests without a username in the Request-URI but one
# of our domains or IPs are addressed to the proxy itself and
# can be answered statelessly.
if (is_method("OPTIONS"))
{
sl_send_reply("200","OK");
exit;
}
if ($fU=="ping")
{
sl_send_reply("200","OK");
exit;
}
# extract original source ip / port from X-forwarded-For header
route(HANDLE_X_FORWARDED_FOR);
# per request initial checks
route(REQINIT);
# NAT detection
route(NATDETECT);
# handle requests within SIP dialogs
### only initial requests (no To tag)
# 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();
xlog("L_INFO", "ROUTE - Exiting after Retransmission check - method $rm");
exit;
}
t_check_trans();
}
route(WITHINDLG);
# record routing for dialog forming requests (in case they are routed)
# - remove preloaded route headers
xlog("L_INFO", "ROUTE - Removing Headers");
remove_hf("Route");
if (is_method("INVITE|SUBSCRIBE")){
t_on_failure("MANAGE_FAILURE");
xlog("L_INFO", "ROUTE - Recording Route");
record_route();
if (is_method("INVITE") && is_request()) {
if (has_body("application/sdp")) {
xlog("L_INFO", "ROUTE - goiing to t_on_reply[ON_REPLY]\n");
t_on_reply("ON_REPLY");
}
}
}
if ($rU==$null)
{
# request with no Username in RURI
sl_send_reply("484","ROUTE - Address Incomplete");
exit;
}
route(TOCARRIER);
xlog("L_INFO", " ********** Route END *************");
}
# extract original source ip / port from X-forwarded-For header
route[HANDLE_X_FORWARDED_FOR] {
if (is_present_hf("X-Forwarded-For")) {
$var(source_ip) = $(hdr(X-Forwarded-For){s.select,0,:});
$var(source_port) = $(hdr(X-Forwarded-For){s.select,1,:});
} else {
$var(source_ip) = $si;
$var(source_port) = $sp;
}
$var(to_number) = $rU;
}
route[RELAY_API] {
xlog("L_INFO","RELAY_API - from_ip $var(source_ip):$var(source_port)
from_number $fU to_number $ru");
$http_req(all) = $null;
$http_req(suspend) = 1;
$http_req(timeout) = HTTP_API_TIMEOUT;
$http_req(method) = "POST";
$http_req(hdr) = "Content-Type: application/json";
jansson_set("string","from_ip",$var(source_ip), "$var(http_routing_query)");
jansson_set("string","from_port",$var(source_port), "$var(http_routing_query)");
jansson_set("string","from_number",$fU, "$var(http_routing_query)");
jansson_set("string","to_number",$var(to_number) , "$var(http_routing_query)");
xlog("L_INFO","RELAY_API - API ASYNC ROUTING REQUEST:
$var(http_routing_query)\n");
$http_req(body) = $var(http_routing_query);
t_newtran();
http_async_query(HTTP_API_ROUTING_ENDPOINT, "RELAY_API_RESPONSE");
}
# Relay request using the API (response)
route[RELAY_API_RESPONSE] {
if ($http_ok==1 && $http_rs==200)
{
xlog("L_INFO","RELAY_API_RESPONSE - RESPONSE: $http_rb\n");
if (jansson_get("rtjson", $http_rb, "$var(rtjson)")) {
xlog("L_INFO","RELAY_API_RESPONSE - $var(rtjson)");
rtjson_init_routes("$var(rtjson)");
rtjson_push_routes();
# relay the message
t_on_branch("MANAGE_BRANCH");
t_on_failure("MANAGE_FAILURE");
route(RELAY);
return;
}
}
send_reply(500, "API Not Available - http response = $http_rs $http_ok");
exit;
}
onreply_route[ON_REPLY] {
xlog("L_INFO", "ON_REPLY - In onreply_route[ON_REPLY] $rs");
# on reply
if (t_check_status("183|180|200")) {
xlog("L_INFO", "ON_REPLY - Fixing Contacts");
# subst_hf("Contact","/@.*:/@EXTERNAL_IP_ADDR:/","a");
//subst_hf("Record-Route","/INTERNAL_IP_ADDR/EXTERNAL_IP_ADDR/","f");
}
if (has_body("application/sdp")){
if (sdp_remove_line_by_prefix("a=maxptime")){
xlog("L_INFO", "ON_REPLY - remove maxptime ");
msg_apply_changes();
}
else{
xlog("L_INFO", "ON_REPLY - did not removed maxptime ");
}
}
if (t_check_status("408")) {
xlog("L_INFO", "ROUTE - Handling 408 Timeout\n");
}
}
route[TOCARRIER]{
#using rtjson, unsomment following line
route(RELAY_API);
}
# Per SIP request initial checks
route[REQINIT] {
xlog("L_INFO", "REQINIT - Starting");
if (!mf_process_maxfwd_header("10")) {
xlog("L_INFO", "REQINIT - 483 - Too Many Hops");
sl_send_reply("483","Too Many Hops");
exit;
}
if(!sanity_check("1511", "7"))
{
xlog("L_INFO","REQINIT - Sanity Check -> Malformed SIP message from $si:$sp\n");
exit;
}
}
# Caller NAT detection
route[NATDETECT] {
xlog("L_INFO", "NATDETECT - Entering");
#!ifdef WITH_NAT
force_rport();
if (nat_uac_test("19")) {
if (is_method("REGISTER")) {
xlog("L_INFO", "NATDETECT - Fix Nated Register");
fix_nated_register();
} else {
if(is_first_hop()){
xlog("L_INFO", "NATDETECT - Set Contact Alias");
set_contact_alias();
}
}
xlog("L_INFO", "NATDETECT - Set FLT_NATS" + FLT_NATS);
setflag(FLT_NATS);
}
#!endif
xlog("L_INFO", "NATDETECT - NAT Detect set FLT_NTS = " + FLT_NATS);
return;
}
# Handle requests within SIP dialogs
route[WITHINDLG] {
xlog("L_INFO", "WITHINDLG - Entering");
if (!has_totag()) return;
if (is_present_hf("Route") && $hdrc(Route)==1)
{
if (search_hf("Route", ".*EXTERNAL_IP_ADDR.*", "f"))
{
xlog("L_INFO", "WITHINDLG - Removing the route to self");
remove_hf("Route");
}
}
# sequential request within a dialog should
# take the path determined by record-routing
if (loose_route()) {
route(DLGURI);
if (is_method("BYE|CANCEL")) {
setflag(FLT_ACC); # do accounting ...
setflag(FLT_ACCFAILED); # ... even if the transaction fails
}
else if ( is_method("ACK") ) {
# ACK is forwarded statelessy
xlog("L_INFO", "WITHINDLG - Going to NATMANAGE");
route(NATMANAGE);
}
else if ( is_method("NOTIFY") ) {
#Add Record-Route for in-dialog NOTIFY as per RFC 6665.
record_route();
}
if(is_method("BYE"))
xlog("L_INFO", "WITHINDLG - BYE message from $rU");
route(RELAY);
exit;
}
if ( is_method("ACK|BYE|INVITE|UPDATE") ) {
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. Try to route anyway - being optimistic
# since it has at least a To Tag
route(RELAY);
exit;
}
}
sl_send_reply("404","Not here");
xlog("L_INFO", "WITHINDLG - Finishing WITHINDLG");
exit;
}
# URI update for dialog requests
route[DLGURI] {
xlog("L_INFO", "WITHINDLG - Entering DLGURI");
#!ifdef WITH_NAT
if(!isdsturiset()) {
xlog("L_INFO", "WITHINDLG - Handle ruri ALIAS");
handle_ruri_alias();
}
#!endif
return;
}
# Routing to foreign domains ---> NOT USED
route[SIPOUT] {
xlog("L_INFO", "WITHINDLG - Entering SIPOUT");
if (uri==myself){
xlog("L_INFO", "WITHINDLG - URI is MySelf!");
return;
}
append_hf("P-hint: outbound\r\n");
xlog("L_INFO", "WITHINDLG - Finishing SIPOUT");
route(RELAY);
exit;
}
# Wrapper for relaying requests
route[RELAY] {
xlog("L_INFO", " ******** RELAY *******");
xlog("L_INFO", "RELAY - $si $su $ru");
# enable additional event routes for forwarded requests
# - serial forking, RTP relaying handling, a.s.o.
if (is_method("INVITE|BYE|CANCEL|SUBSCRIBE|UPDATE")) {
if(!t_is_set("branch_route")) {
xlog("L_INFO", "RELAY - branch_route NOT SET!");
t_on_branch("MANAGE_BRANCH");
}
}
xlog("L_INFO", "RELAY - checking method");
if (is_method("INVITE|SUBSCRIBE|UPDATE")) {
xlog("L_INFO", "RELAY - is INVITE|SUBSCRIBE|UPDATE");
if(!t_is_set("onreply_route")) {
xlog("L_INFO", "RELAY - onreply_route NOT SET!");
t_on_reply("ON_REPLY"); # MANAGE_REPLY");
}
}
if (is_method("INVITE")) {
xlog("L_INFO", "RELAY - is INVITE");
t_on_failure("FAILED_RELAY");
if(!t_is_set("failure_route")) {
xlog("L_INFO", "RELAY - failure_route NOT SET!");
t_on_failure("MANAGE_FAILURE");
}
}
if (!t_relay()) {
xlog("L_INFO", "RELAY - t_relay returns FALSE");
route("MANAGE_FAILURE");
#sl_reply_error();
}
xlog("L_INFO", "RELAY - exiting");
exit;
}
failure_route[FAILED_RELAY] {
xlog("L_INFO", "FAILED_RELAY - Entering");
if (t_check_status("[4-5][0-9][0-9]")){
xlog("L_INFO", "FAILED_RELAY - Could not reach destination endpoint!");
if (rtjson_next_route()) {
xlog("L_INFO", "MANAGE_FAILURE - Getting next route");
t_on_branch("MANAGE_BRANCH");
t_on_failure("MANAGE_FAILURE");
route(RELAY);
}
}
}
route[NATMANAGE] {
xlog("L_INFO", "NATMANAGE - Entering");
#!ifdef WITH_NAT
if (is_request()) {
if(has_totag()) {
xlog("L_INFO", "NATMANAGE - nat=yes --- Setting FLB_NATB");
setbflag(FLB_NATB);
}
}
if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB) ))
{
xlog("L_INFO", "NATMANAGE - NO FLT_NATS/B Set!!! Getting
out of NATMANAGE");
return;
}
if (is_request()) {
xlog("L_INFO", "NATMANAGE - is_request - $rm from $si");
if (!has_totag()) {
if(t_is_branch_route()) {
xlog("L_INFO", "NATMANAGE - adding nat=yes");
add_rr_param(";nat=yes");
}
}
}
if (is_reply()) {
xlog("L_INFO", "NATMANAGE - is_reply - $rm from $si");
if(isbflagset(FLB_NATB)) {
if(is_first_hop())
{
xlog("L_INFO", "NATMANAGE - Set Contact Alias");
set_contact_alias();
}
}
}
#!endif
return;
}
# Manage failure routing cases
route[MANAGE_FAILURE] {
xlog("L_INFO", "MANAGE_FAILURE - Entering ");
route(NATMANAGE);
xlog("L_INFO", "MANAGE_FAILURE - t_is_canceled");
if (t_is_canceled()) exit;
#!ifdef WITH_BLOCK3XX
# block call redirect based on 3xx replies.
if (t_check_status("3[0-9][0-9]")) {
xlog("L_INFO", "MANAGE_FAILURE - SIP 3XX returned!!");
t_reply("404","Not found");
exit;
}
#!endif
#!ifdef WITH_BLOCK401407
# block call redirect based on 401, 407 replies.
if (t_check_status("401|407")) {
xlog("L_INFO", "MANAGE_FAILURE - SIP 401|407 returned!!");
t_reply("404","Not found");
exit;
}
#!endif
if (t_check_status("503")){
xlog("L_INFO", "MANAGE_FAILURE - SIP 503 returned : no destination available");
t_reply("503", "Destination not available");
exit;
}
if (rtjson_next_route()) {
xlog("L_INFO", "MANAGE_FAILURE - Getting next route!!");
t_on_branch("MANAGE_BRANCH");
t_on_failure("MANAGE_FAILURE");
route(RELAY);
exit;
}
}
# Manage outgoing branches
branch_route[MANAGE_BRANCH] {
xlog("L_INFO","MANAGE_BRANCH - New branch [$T_branch_idx] to $ru\n");
xlog("L_INFO", "MANAGE_BRANCH - branch_route MANAGE_BRANCH 1 ");
rtjson_update_branch();
route(NATMANAGE);
}
Any help would be greatly appreciated.
Thanks in advance.
Sérgio Charrua