To get the IP address from the SDP part of incoming INVITE:
$(rb{sdp.line,c}{s.select,2, })
http://lists.opensips.org/pipermail/users/2024-June/048189.html
To get the IP address from the SDP part of incoming INVITE:
$(rb{sdp.line,c}{s.select,2, })
http://lists.opensips.org/pipermail/users/2024-June/048189.html
Just some explanation of dispatcher module argorithms.
hash over callid
– ensures that all requests within a dialog goes to same boxhash over from uri
– ensures that all requests from same user goes to same boxhash over to uri
– ensures that registrations of an AoR goes to same boxhash over request-uri
– ensures that requests to same destination are processes by same box#hash over config variable
– for different needs
This guide will help you to understand how OpenSIPS can be monitored with Zabbix, sharing its statistic data via HTTP interface in JSON format. This article assumes using OpenSIPS 3.2 and Zabbix 6.
Enable embedded HTTP server and HTTP support for Management Interface in your OpenSIPS:
loadmodule "httpd.so" modparam("httpd", "ip", "192.168.88.244") modparam("httpd", "port", 8888) # :8888/mi loadmodule "mi_http.so" modparam("mi_http", "root", "mi")
Now we may try to send a JSON-RPC OpenSIPS MI command from the command-line, using curl (official example at the very bottom of the page):
/usr/bin/curl -X POST 192.168.88.244:8888/mi -H 'Content-Type: application/json' -d '{"jsonrpc": "2.0", "id": "1", "method": "uptime"}'
The official documentation does not have other more complicated examples, e.g. “get_statistics sl:”, that’s why I decided to write this article, maybe it’s more about JSON, JSONPath and working with all this in Zabbix.
As an example, we’ll get stateless replier module statistics, like shown by invoking a CLI command “opensips-cli -x mi get_statistics sl:” .
/usr/bin/curl -X POST 192.168.88.244:8888/mi -H 'Content-Type: application/json' -d '{"jsonrpc": "2.0", "id": "1", "method": "get_statistics", "params": {"statistics": ["sl:"]}}'
I’ll also duplicate the command with a screenshot (to be sure that you see it in a right way, because markup may cut some special characters):
Tip: if you need statistics from several groups, for example several modules (not only SL), the request will be as follows:
/usr/bin/curl -X POST 192.168.88.244:8888/mi -H 'Content-Type: application/json' -d '{"jsonrpc": "2.0", "id": "1", "method": "get_statistics", "params": {"statistics": ["sl:", "tm:"]}}'
OpenSIPS will answer and you’ll see SL module statistics after sending this request with CURL.
But the responce is a one-liner, so we need to convert this one line to JSON format and then to create a JSONPath, to be able to extract the value we need.
Let’s monitor not all SL module statistics received from OpenSIPS, but the number of 2xx replies only.
I use https://www.jsonformatter.io/ for JSON formatting and https://jsonpath.com/ for creating JSONPath. After formatting and specifying JSONPath we can configure Zabbix.
Now it’s time to add items to your OpenSIPS host in Zabbix. Item parameters:
Type: HTTP Agent Type of information: Numeric (unsigned) Request type: POST Request body type: JSON data Request body: {"jsonrpc": "2.0", "id": "1", "method": "get_statistics", "params": {"statistics": ["sl:"]}} Retrieve mode: Body Convert to JSON (enabled)
Screenshots as usual:
Item Preprocessing parameters:
1st step - JSONPath Parameters: $.body.result.["sl:2xx_replies"] Type of information: Numeric (unsigned)
Screen – item Preprocessing and successful testing:
Now we add a graph with this item (I hope you know how to create graphs in Zabbix) and it’s time to test. I will generate thousands of OPTIONS requests to my OpenSIPS with the sipp tool (I also recommend this sipp cheatsheet).
Download OPTIONS.xml scenario file, and generate 10000 OPTIONS requests with call rate of 10 (I assume that your OpenSIPS, like mine, answers “200 OK”):
sipp 192.168.88.244 -sf OPTIONS.xml -l 10000 -m 10000 -r 10
Finally, here is the graph showing your OpenSIPS SL module 2xx processed replies statistics:
This is how you can monitor OpenSIPS with Zabbix using JSON.
Have fun!
Undocumented feature –
how to configure weight for a rtpengine set (default value is 1):
modparam("rtpengine", "rtpengine_sock", "udp:localhost:12222=2")
http://lists.opensips.org/pipermail/users/2021-August/045084.html
No DB, node 1:
modparam("clusterer", "current_id", 1) modparam("clusterer", "db_mode", 0) modparam("clusterer", "seed_fallback_interval", 10) # Only relevant for seed node modparam("clusterer", "current_info","cluster_id=1,url=bin:10.145.213.63:5555,flags=seed") modparam("clusterer", "neighbor_info","cluster_id=1,node_id=2,url=bin:10.145.213.155:5555")
No DB, node 2:
modparam("clusterer", "current_id", 2) modparam("clusterer", "db_mode", 0) modparam("clusterer", "seed_fallback_interval", 10) # Only relevant for seed node modparam("clusterer", "current_info", "cluster_id=1,url=bin:10.145.213.155:5555") modparam("clusterer", "neighbor_info", "cluster_id=1,node_id=1,url=bin:10.145.213.63:5555")
DB configuration, node 1:
modparam("clusterer", "current_id", 1) modparam("clusterer", "db_mode", 1) modparam("clusterer", "db_url", "mysql://opensips:MeGaPaSs@10.145.213.200/opensips")
DB configuration, node 2:
modparam("clusterer", "current_id", 2) modparam("clusterer", "db_mode", 1) modparam("clusterer", "db_url", "mysql://opensips:MeGaPaSs@10.145.213.200/opensips")
Clusterer table:
MariaDB [dbsrv]> select * from clusterer\G *************************** 1. row *************************** id: 1 cluster_id: 1 node_id: 1 url: bin:10.145.213.63:5555 state: 1 no_ping_retries: 3 priority: 50 sip_addr: flags: seed description: USRLOC_Cluster_node_1 *************************** 2. row *************************** id: 2 cluster_id: 1 node_id: 2 url: bin:10.145.213.155:5555 state: 1 no_ping_retries: 3 priority: 50 sip_addr: flags: description: USRLOC_Cluster_node_2
This is about adding a display name to the calls from registered users. An analogue of Asterisk’s Set(CALLERID(name)=John Doe).
The idea was to move SIP accounts from Asterisk to OpenSIPS.
In case of using Asterisk we would configure something like:
[user222]
context=o.local
secret=4EwIWikV
callerid=Alexey Kazantsev <222>
How to achieve the same with OpenSIPS? This is the solution:
modparam("auth_db", "load_credentials", "$avp(display)=rpid")
modparam("registrar", "attr_avp", "$avp(display)")
# call from registered user -> add callerid
# and forward to mediaserver for call recording, etc.
if(is_registered("location"))
{
# replace only display and do not touch uri
uac_replace_from("$avp(display)","");
rewritehostport("10.145.213.63:5067");
route(relay);
}
How it looks like?
This is the INVITE coming to OpenSIPS:
2019/11/21 14:16:55.247856 10.145.213.64:5061 -> 10.145.213.63:5060
INVITE sip:111@taxsee.com SIP/2.0
Via: SIP/2.0/UDP 10.145.213.64:5061;branch=z9hG4bK-3822b894
From: <sip:222@taxsee.com>;tag=48b014547f398294o1
And this is the same INVITE leaving OpenSIPS, being modified:
2019/11/21 14:16:55.252518 10.145.213.63:5060 -> 10.145.213.63:5067
INVITE sip:111@10.145.213.63:5067 SIP/2.0
Record-Route: <sip:10.145.213.63;lr;ftag=48b014547f398294o1>
Via: SIP/2.0/UDP 10.145.213.63:5060;branch=z9hG4bK77e6.9bb3aa72.0
Via: SIP/2.0/UDP 10.145.213.64:5061;branch=z9hG4bK-3822b894
From: "Alexey Kazantsev" <sip:222@taxsee.com>;tag=48b014547f398294o1
The information stored in the ‘rpid’ column (in our example, or some custom in your architecture) is fetched to AVP at each REGISTER/save, so you do not need to reload anything to take changes in effect.
The callerid info is seen in console output via ‘opensipsctl fifo ul_dump’ command:
AOR:: 222@taxsee.com
Contact:: sip:222@10.145.213.64:5061 Q=
ContactID:: 3039507536010050217
Expires:: 42
Callid:: 9fdd26c2-6de37105@10.145.213.64
Cseq:: 35746
User-agent:: Cisco/SPA303-7.6.2c
State:: CS_NEW
Flags:: 0
Cflags::
Socket:: udp:10.145.213.63:5060
Methods:: 5247
Attr:: Alexey Kazantsev
Let’s imagine that we’ve upgraded our VoIP network which was formerly based on geographically distributed Asterisks.
We configured OpenSIPS servers as registrars, connected them together in a full-sharing usrloc cluster and now we need to route calls between endpoints not directly, but through Asterisks – to handle our calls in a familiar way (CDR records, call recording via MixMonitor, some AGI scripts, etc).
We have to create something like that:
This is a code snippet of OpenSIPS with IP address 10.145.213.63:
# initial INVITE
if(is_method("INVITE") && !has_totag())
{
t_on_failure("1");
# call from registered user ->
# forward to mediaserver for call recording, etc.
if(is_registered("location"))
{
$ru="sip:" + $oU + "@" + "10.145.213.63:5067";
route(relay);
}
# call from Asterisk? -> change domain part before doing lookup
if($sp=="5067")
{
$rd="taxsee.com";
}
$var(lookup_flags) = "m";
if(cluster_check_addr("1", "$si")) {
xlog("si: $si . $rm from cluster, doing local lookup only\n");
} else {
xlog("si: $si . $rm from outside, doing global lookup\n");
$var(lookup_flags) = $var(lookup_flags) + "g";
}
if(!lookup("location", "$var(lookup_flags)"))
{
t_reply("404", "Not Found");
exit;
}
if(has_body("application/sdp"))
{
rtpengine_offer("RTP/AVP replace-origin replace-session-connection ICE=remove");
}
} # initial INVITE end
route(relay);
A SIP peer to this OpenSIPS in Asterisk sip.conf looks like this:
[opensips]
type=peer
context=office
host=10.145.213.63
port=5060
And a dialplan for CDR/MixMonitor/etc:
context office
{
_XXX =>
{
NoOp(imagine this is CDR, MixMonitor, AGI);
Dial(SIP/opensips/${EXTEN});
Hangup();
};
};
UPD: assuming your SIP acoounts DB has moved from Asterisk to OpenSIPS cluster, its desirable not just processing REGISTER requests and doing authentication, but also adding caller ids to your SIP accounts.
UPD: 2019-november-5. An official tutorial is available now! And some discussion on the mail list.
Draft/some notes…
2 OpenSIPS nodes without MongoDB
Key settings:
loadmodule “usrloc.so”
modparam(“usrloc”, “db_url”, “mysql://opensips:pass@10.145.213.63/opensips”)
modparam(“usrloc”, “nat_bflag”, “NAT”)
modparam(“usrloc”, “working_mode_preset”, “full-sharing-cluster”)
modparam(“usrloc”, “location_cluster”, 1)
modparam(“usrloc”, “use_domain”, 1)
loadmodule “clusterer.so” # requires proto_bin.so
modparam(“clusterer”, “current_id”, 1)
modparam(“clusterer”, “db_mode”, 1)
modparam(“clusterer”, “db_url”, “mysql://opensips:pass@10.145.213.63/opensips”)
# initial INVITE
if(is_method("INVITE")) {
t_on_failure("1");
$var(lookup_flags) = "m";
if (cluster_check_addr("1", "$si")) {
xlog("si: $si . $rm from cluster, doing local lookup only\n");
} else {
xlog("si: $si . $rm from outside, doing global lookup\n");
$var(lookup_flags) = $var(lookup_flags) + "g";
}
if (!lookup("location", "$var(lookup_flags)")) {
t_reply("404", "Not Found");
exit;
}
if (has_body("application/sdp")) {
rtpengine_offer("RTP/AVP replace-origin replace-session-connection ICE=remove");
}
} # initial invite END
UPD: some useful notes from Liviu Chircu: http://lists.opensips.org/pipermail/users/2019-October/041819.html
Pay attention: according to his advice, we don’t need any data in ‘sip_addr’ columns when creating a full-sharing usrloc cluster. In case of federated cluster we have to fill them with IP addresses on which OpenSIPS nodes are listening.
Formerly we’ve learned how to restrict access with permission.so module based on source IP addresses. Today I’ll show how to restrict access to your OpenSIPS based on usernames, being registering.
loadmodule "permissions.so" # no deps
...
if (is_method("REGISTER")) {
if(!allow_register("register")) {
sl_send_reply(403, "Forbidden by permissions");
exit;
}
“Deny all, but …” policy – we will allow registrations of explicitly defined usernames and drop anybody else.
register.deny file:
ALL : ALL
register.allow file:
# this allows lexus, lexus2, lexus3 to register
"^sip:lexus[23]?@alexeyka.zantsev.com" : ALL
# regexp seems to be CORRECT, but for some reason lexus2 and lexus3 can not register
# "^sip:lexus[\d]?@alexeyka.zantsev.com" : ALL
Have a look how it’s working! A good guy is being registered successfully:
While a bad guy had been kicked:
Another solution using regex.so module from Pavel Eremin. The pros of this method is that it allows editing a txt file with usernames defined and reload regex.so module via MI interface (no restart needed).
And even one more from Răzvan Crainea.