444 lines
12 KiB
INI
444 lines
12 KiB
INI
#!KAMAILIO
|
|
#
|
|
# This config file implements the basic P-CSCF functionality
|
|
# - 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.
|
|
#
|
|
# Direct your questions about this file to: <sr-users@lists.kamailio.org>.
|
|
#
|
|
# For more information about the various parameters, functions and statements
|
|
# try http://sip-router.org/wiki/ .
|
|
#
|
|
|
|
include_file "smsc.cfg"
|
|
|
|
####### Global Parameters #########
|
|
debug=2
|
|
log_stderror=no
|
|
sip_warning=no
|
|
children=4
|
|
|
|
user_agent_header="User-Agent: Kamailio SMSC"
|
|
server_header="Server: Kamailio SMSC"
|
|
log_name="smsc"
|
|
log_prefix_mode=1
|
|
log_prefix="{$mt $hdr(CSeq) $ci $cfg(route)} "
|
|
|
|
/* comment the next line to enable the auto discovery of local aliases
|
|
based on reverse DNS on IPs (default on) */
|
|
auto_aliases=no
|
|
|
|
check_via=no # (cmd. line: -v)
|
|
dns=no # (cmd. line: -r)
|
|
rev_dns=no # (cmd. line: -R)
|
|
tcp_accept_no_cl=yes
|
|
|
|
#!define SMS_3GPP 1
|
|
#!define SMS_TEXT 2
|
|
|
|
alias=SMSC_SERVER
|
|
|
|
# ------------------ module loading ----------------------------------
|
|
mpath="/usr/lib64/kamailio/modules_k/:/usr/lib64/kamailio/modules/:/usr/lib/kamailio/modules_k/:/usr/lib/kamailio/modules/:/usr/lib/x86_64-linux-gnu/kamailio/modules/:/usr/local/lib64/kamailio/modules"
|
|
# (we try both the lib64 and the lib directory)
|
|
|
|
loadmodule "tm.so"
|
|
loadmodule "tmx.so"
|
|
loadmodule "smsops.so"
|
|
loadmodule "xlog.so"
|
|
loadmodule "maxfwd.so"
|
|
loadmodule "textops.so"
|
|
loadmodule "sl.so"
|
|
loadmodule "sanity.so"
|
|
loadmodule "siputils.so"
|
|
loadmodule "pv.so"
|
|
loadmodule "uac.so"
|
|
loadmodule "http_client.so"
|
|
loadmodule "xhttp.so"
|
|
loadmodule "utils.so"
|
|
loadmodule "json.so"
|
|
loadmodule "enum.so"
|
|
loadmodule "db_mysql.so"
|
|
loadmodule "dialplan.so"
|
|
loadmodule "sqlops.so"
|
|
loadmodule "htable.so"
|
|
loadmodule "rtimer.so"
|
|
loadmodule "usrloc.so"
|
|
loadmodule "registrar.so"
|
|
loadmodule "pua.so"
|
|
loadmodule "pua_reginfo.so"
|
|
|
|
modparam("sqlops", "sqlcon", SMS_DB_URL)
|
|
modparam("dialplan", "db_url", DIALPLAN_PUA_DB_URL)
|
|
modparam("uac", "restore_mode", "none")
|
|
|
|
modparam("htable", "htable", "publish_sent=>size=8;autoexpire=SUBSCRIBE_EXPIRE")
|
|
modparam("htable", "htable", "sms_retries=>size=8;autoexpire=SUBSCRIBE_EXPIRE")
|
|
|
|
# time interval set to 3 seconds
|
|
modparam("rtimer", "timer", "name=sms;interval=3;mode=1;")
|
|
modparam("rtimer", "exec", "timer=sms;route=SMS_WORKER")
|
|
|
|
modparam("pua_reginfo", "server_address", "sip:SMSC_SERVER")
|
|
modparam("pua_reginfo", "publish_reginfo", 0)
|
|
modparam("pua", "db_url", DIALPLAN_PUA_DB_URL)
|
|
|
|
####### Routing Logic ########
|
|
# Main SIP request routing logic
|
|
# - processing of any incoming SIP request starts with this route
|
|
|
|
route {
|
|
xlog("L_DBG", "$rm ($fu ($si:$sp) to $tu, $ci)\n");
|
|
|
|
# per request initial checks
|
|
route(REQINIT);
|
|
|
|
if (is_method("NOTIFY")) {
|
|
route(NOTIFY);
|
|
send_reply("202", "Accepted");
|
|
exit;
|
|
}
|
|
|
|
if (!is_method("MESSAGE")) {
|
|
append_to_reply("Allow: MESSAGE,NOTIFY\r\n");
|
|
send_reply("405", "Method not allowed");
|
|
exit;
|
|
}
|
|
|
|
if ($cT == "application/vnd.3gpp.sms") {
|
|
route(SMS_FROM_3GPP);
|
|
} else if ($cT == "text/plain") {
|
|
route(SMS_FROM_SIP);
|
|
} else {
|
|
send_reply("488", "Content-Type not supported");
|
|
exit;
|
|
}
|
|
}
|
|
|
|
######################################################################
|
|
# Helper routes (Basic-Checks, NAT-Handling/RTP-Control, XML-RPC)
|
|
######################################################################
|
|
# Per SIP request initial checks
|
|
route[REQINIT] {
|
|
# Trace this message
|
|
|
|
if (!mf_process_maxfwd_header("10")) {
|
|
sl_send_reply("483","Too Many Hops");
|
|
exit;
|
|
}
|
|
|
|
if(!sanity_check("1511", "7")) {
|
|
xlog("Malformed SIP message from $si:$sp\n");
|
|
exit;
|
|
}
|
|
|
|
# Reply to OPTIONS:
|
|
if (is_method("OPTIONS") && (uri==myself)) {
|
|
options_reply();
|
|
exit;
|
|
}
|
|
|
|
# Ignore Re-Transmits:
|
|
if (t_lookup_request()) {
|
|
exit;
|
|
}
|
|
}
|
|
|
|
######################################################################
|
|
# SMS from VoLTE Handsets
|
|
######################################################################
|
|
route[SMS_FROM_3GPP] {
|
|
#!ifdef WITH_DEBUG
|
|
xlog("3GPP-SMS: $rm ($fu ($si:$sp) to $tu, $ci)\n");
|
|
xlog("SMS for $tpdu(destination) \"$tpdu(payload)\" (Valid: $tpdu(validity) )\n");
|
|
#!endif
|
|
send_reply("202", "Accepted");
|
|
|
|
if (isRPDATA()) {
|
|
$uac_req(method) = "MESSAGE";
|
|
$uac_req(ruri) = $ai;
|
|
$uac_req(furi) = "sip:"+SMSC_SERVER;
|
|
$uac_req(turi) = $ai;
|
|
$uac_req(hdrs) = "Content-Type: application/vnd.3gpp.sms\r\nRequest-Disposition: no-fork\r\nAccept-Contact: *;+g.3gpp.smsip\r\n";
|
|
$uac_req(body) = $smsack;
|
|
uac_req_send();
|
|
|
|
|
|
$avp(from) = $(ai{uri.user});
|
|
$avp(to) = $tpdu(destination);
|
|
$avp(dcs) = $tpdu(coding);
|
|
# Translate "To":
|
|
dp_translate("1", "$avp(to)/$avp(to)");
|
|
|
|
$avp(text) = $tpdu(payload);
|
|
#!ifdef WITH_DEBUG
|
|
xlog("SMS from 3GPP/VoLTE\n");
|
|
xlog("-------------------------------------\n");
|
|
xlog("FROM $avp(from)\n");
|
|
xlog("TO $avp(to)\n");
|
|
xlog("TEXT $avp(text)\n");
|
|
xlog("DCS $avp(dcs)\n");
|
|
#!endif
|
|
route(SMS);
|
|
}
|
|
|
|
exit;
|
|
}
|
|
|
|
######################################################################
|
|
# SMS from OTT Handsets
|
|
######################################################################
|
|
route[SMS_FROM_SIP] {
|
|
send_reply("200", "OK");
|
|
|
|
$avp(from) = $(ai{uri.user});
|
|
# Translate "To":
|
|
$avp(to) = $tU;
|
|
dp_translate("1", "$avp(to)/$avp(to)");
|
|
$avp(text) = $rb;
|
|
#!ifdef WITH_DEBUG
|
|
xlog("SMS from SIP/OTT\n");
|
|
xlog("-------------------------------------\n");
|
|
xlog("FROM $avp(from)\n");
|
|
xlog("TO $avp(to)\n");
|
|
xlog("TEXT $avp(text)\n");
|
|
#!endif
|
|
route(SMS);
|
|
|
|
exit;
|
|
}
|
|
|
|
|
|
######################################################################
|
|
# SMS from other networks
|
|
######################################################################
|
|
event_route[xhttp:request] {
|
|
if ($(hu{url.querystring}{s.len}) > 0) {
|
|
$avp(from) = $(hu{url.querystring}{param.value,msisdn,&});
|
|
$avp(to) = $(hu{url.querystring}{param.value,to,&});
|
|
$avp(text) = $(hu{url.querystring}{param.value,text,&}{s.replace,+,%20}{s.unescape.user});
|
|
$avp(from_outbound) = 1;
|
|
#!ifdef WITH_DEBUG
|
|
xlog("SMS from Outbound ($hu)\n");
|
|
xlog("-------------------------------------\n");
|
|
xlog("FROM $avp(from)\n");
|
|
xlog("TO $avp(to)\n");
|
|
xlog("TEXT $avp(text)\n");
|
|
#!endif
|
|
if ($avp(to) == "491771782261")
|
|
$avp(to) = "494046895124";
|
|
if ($avp(to) == "491771782319")
|
|
$avp(to) = "494034927220";
|
|
|
|
route(SMS);
|
|
}
|
|
|
|
xhttp_reply("200", "OK", "text/html", "<html><body>OK - [$si:$sp]</body></html>");
|
|
}
|
|
|
|
######################################################################
|
|
# SMS to VoLTE Handsets
|
|
######################################################################
|
|
route[SMS_TO_3GPP] {
|
|
#!ifdef WITH_DEBUG
|
|
xlog("SMS to 3GPP/VoLTE\n");
|
|
xlog("-------------------------------------\n");
|
|
xlog("FROM $avp(from)\n");
|
|
xlog("TO $avp(to)\n");
|
|
xlog("TEXT $avp(text)\n");
|
|
xlog("DCS $avp(dcs)\n");
|
|
#!endif
|
|
|
|
// Construct a new SMS-Body:
|
|
$rpdata(all) = $null;
|
|
$rpdata(type) = 1; // RP-DATA: Network to UE
|
|
$rpdata(reference) = $avp(id);
|
|
$rpdata(originator) = $avp(from);
|
|
$tpdu(type) = 4; // SMS-Deliver
|
|
$tpdu(origen) = $avp(from); // The Destination becomes the originator of the SMS
|
|
$tpdu(payload) = $avp(text);
|
|
$tpdu(coding) = $avp(dcs);
|
|
|
|
$uac_req(method) = "MESSAGE";
|
|
$uac_req(ruri) = "sip:"+$avp(to)+"@"+DOMAIN;
|
|
$uac_req(furi) = "sip:"+SMSC_SERVER;
|
|
$uac_req(turi) = "sip:"+$avp(to)+"@"+DOMAIN;
|
|
$uac_req(hdrs) = "Content-Type: application/vnd.3gpp.sms\r\nRequest-Disposition: no-fork\r\nAccept-Contact: *;+g.3gpp.smsip\r\nX-MSG-ID: "+$avp(id)+"\r\n";
|
|
$uac_req(body) = $smsbody;
|
|
$uac_req(evroute)=1;
|
|
uac_req_send();
|
|
# sql_query("sms", "delete from messages where id=$avp(id);");
|
|
}
|
|
|
|
######################################################################
|
|
# SMS to OTT-Handsets
|
|
######################################################################
|
|
route[SMS_TO_SIP] {
|
|
#!ifdef WITH_DEBUG
|
|
xlog("SMS to SIP/OTT\n");
|
|
xlog("-------------------------------------\n");
|
|
xlog("FROM $avp(from)\n");
|
|
xlog("TO $avp(to)\n");
|
|
xlog("TEXT $avp(text)\n");
|
|
#!endif
|
|
|
|
$uac_req(method) = "MESSAGE";
|
|
$uac_req(ruri) = "sip:"+$avp(to)+"@"+DOMAIN;
|
|
$uac_req(furi) = "sip:+"+$avp(from)+"@"+DOMAIN;
|
|
$uac_req(turi) = "sip:"+$avp(to)+"@"+DOMAIN;
|
|
$uac_req(hdrs) = "Content-Type: text/plain\r\nX-MSG-ID: "+$avp(id)+"\r\n";
|
|
$uac_req(evroute)=1;
|
|
$uac_req(body) = $avp(text);
|
|
|
|
uac_req_send();
|
|
}
|
|
|
|
######################################################################
|
|
# SMS to Outbound
|
|
######################################################################
|
|
route[SMS_TO_OUTBOUND] {
|
|
#!ifdef WITH_DEBUG
|
|
xlog("SMS to Outbound\n");
|
|
xlog("-------------------------------------\n");
|
|
xlog("FROM $avp(from)\n");
|
|
xlog("TO $avp(to)\n");
|
|
xlog("TEXT $avp(text)\n");
|
|
#!endif
|
|
if ($avp(from_outbound) == 1) {
|
|
xlog("Not sending: FROM and TO Outbound!\n");
|
|
return 1;
|
|
exit;
|
|
}
|
|
if ($avp(from) == "494046895124")
|
|
$avp(from) = "491771782261";
|
|
if ($avp(from) == "494034927220")
|
|
$avp(from) = "491771782319";
|
|
|
|
http_client_query("https://rest.nexmo.com/sms/json?api_key=NEXMO_APIKEY&api_secret=NEXMO_APISECRET&from=$avp(from)&to=$avp(to)&text=$(avp(text){s.escape.user})", "$var(result)");
|
|
if ($retcode != 200) return -1;
|
|
json_get_field("$var(result)", "messages", "$var(messages)");
|
|
json_get_field("$var(messages)", "status", "$var(status)");
|
|
if ($var(status) != 0) return -1;
|
|
return 1;
|
|
}
|
|
|
|
######################################################################
|
|
# SMS Handling
|
|
######################################################################
|
|
route[SMS] {
|
|
#!ifdef WITH_DEBUG
|
|
xlog("SMS-Task\n");
|
|
xlog("-------------------------------------\n");
|
|
xlog("FROM $avp(from)\n");
|
|
xlog("TO $avp(to)\n");
|
|
xlog("TEXT $avp(text)\n");
|
|
xlog("DCS $avp(dcs)\n");
|
|
#!endif
|
|
|
|
# Query ENUM: Local number?
|
|
$var(enum) = "+"+$avp(to);
|
|
if (!enum_pv_query("$var(enum)")) {
|
|
route(SMS_TO_OUTBOUND);
|
|
return $retcode;
|
|
}
|
|
if (sql_query("sms", "insert into messages (caller, callee, text, dcs, valid) values ('$(avp(from){s.escape.common})', '$(avp(to){s.escape.common})', '$(avp(text){s.escape.common})', $avp(dcs), now());"))
|
|
return 1;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
######################################################################
|
|
# SMS Handling
|
|
######################################################################
|
|
route[SMS_WORKER] {
|
|
sql_query("sms", "select id, caller, callee, text, dcs from messages;", "q");
|
|
if ($dbr(q=>rows) > 0) {
|
|
$var(i) = 0;
|
|
while ($var(i) < $dbr(q=>rows)) {
|
|
if ($sht(sms_retries=>$dbr(q=>[$var(i),0])) == $null) {
|
|
$sht(sms_retries=>$dbr(q=>[$var(i),0])) = 0;
|
|
} else {
|
|
$sht(sms_retries=>$dbr(q=>[$var(i),0])) = $sht(sms_retries=>$dbr(q=>[$var(i),0])) + 1;
|
|
}
|
|
|
|
if ($sht(sms_retries=>$dbr(q=>[$var(i),0])) > 2) {
|
|
xlog("Dropping SMS [$dbr(q=>[$var(i),3])] TO $dbr(q=>[$var(i),2]) after 2 retries \n");
|
|
sql_query("sms", "delete from messages where id=$dbr(q=>[$var(i),0]);");
|
|
$sht(sms_retries=>$dbr(q=>[$var(i),0])) = $null;
|
|
} else {
|
|
$avp(id) = $dbr(q=>[$var(i),0]);
|
|
$avp(from) = $dbr(q=>[$var(i),1]);
|
|
$avp(to) = $dbr(q=>[$var(i),2]);
|
|
$avp(text) = $dbr(q=>[$var(i),3]);
|
|
$avp(dcs) = $dbr(q=>[$var(i),4]);
|
|
|
|
route(SEND_SMS);
|
|
#!ifdef WITH_DEBUG
|
|
xlog("ID $avp(id)\n");
|
|
xlog("FROM $avp(from)\n");
|
|
xlog("TO $avp(to)\n");
|
|
xlog("TEXT $avp(text)\n");
|
|
xlog("DCS $avp(dcs)\n");
|
|
#!endif
|
|
}
|
|
|
|
$var(i) = $var(i) + 1;
|
|
}
|
|
}
|
|
sql_result_free("q");
|
|
}
|
|
|
|
route[NOTIFY] {
|
|
if (has_body("application/reginfo+xml")) {
|
|
if (reginfo_handle_notify("location"))
|
|
send_reply("202", "Accepted");
|
|
} else {
|
|
send_reply("503", "Invalid Content-Type");
|
|
}
|
|
exit;
|
|
}
|
|
|
|
route[SEND_SMS] {
|
|
$var(uri) = "sip:"+$avp(to)+"@"+DOMAIN;
|
|
|
|
if (reg_fetch_contacts("location", "$var(uri)", "caller")) {
|
|
$var(j) = 0;
|
|
$var(is3gpp) = 0;
|
|
while($var(j) < $(ulc(caller=>count))) {
|
|
$var(k) = 0;
|
|
while($var(k) < $(ulc(caller=>addr)[$var(j)]{param.count})) {
|
|
if ($(ulc(caller=>addr)[$var(j)]{param.name,$var(k)}) == "+g.3gpp.smsip")
|
|
$var(is3gpp) = 1;
|
|
$var(k) = $var(k) + 1;
|
|
}
|
|
if ($var(is3gpp) == 1)
|
|
route(SMS_TO_3GPP);
|
|
else
|
|
route(SMS_TO_SIP);
|
|
$var(j) = $var(j) + 1;
|
|
}
|
|
} else {
|
|
if ($sht(publish_sent=>$var(uri)) == $null) {
|
|
reginfo_subscribe("$var(uri)", "SUBSCRIBE_EXPIRE");
|
|
$sht(publish_sent=>$var(uri)) = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
event_route [tm:local-request] {
|
|
if (is_method("SUBSCRIBE")) {
|
|
append_hf("P-Asserted-Identity: $ru\r\n");
|
|
}
|
|
}
|
|
|
|
event_route[uac:reply] {
|
|
if (($uac_req(evtype) == 1) && ($uac_req(evcode) == 200) && ($uac_req(hdrs) != $null) && ($uac_req(hdrs) != "")) {
|
|
$var(msgid) = $(uac_req(hdrs){line.sw,X-MSG-ID:}{s.substr,10,0}{s.int});
|
|
sql_query("sms", "delete from messages where id=$var(msgid);");
|
|
}
|
|
}
|
|
|