Created
May 13, 2013 12:57
-
-
Save iwanbk/5568135 to your computer and use it in GitHub Desktop.
kamailio.cfg with SIP over websocket. Modified from kamailio 4.0.1 example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!KAMAILIO | |
# | |
# Simple/sample kamailio.cfg for running a proxy/registrar with TLS and | |
# WebSockets support. | |
###!substdef "!DBURL!sqlite:///etc/kamailio/db.sqlite!g" | |
#!substdef "!DBURL!mysql://kamailio:kamailiorw@localhost/kamailio!g" | |
#!substdef "!MY_IP_ADDR!10.0.11.175!g" | |
#!substdef "!MY_DOMAIN!ubukam.lan!g" | |
#!substdef "!MY_WS_PORT!5065!g" | |
#!substdef "!MY_WSS_PORT!443!g" | |
#!substdef "!MY_MSRP_PORT!9000!g" | |
#!substdef "!MY_WS_ADDR!tcp:MY_IP_ADDR:MY_WS_PORT!g" | |
#!substdef "!MY_WSS_ADDR!tls:MY_IP_ADDR:MY_WSS_PORT!g" | |
#!substdef "!MY_MSRP_ADDR!tls:MY_IP_ADDR:MY_MSRP_PORT!g" | |
#!substdef "!MSRP_MIN_EXPIRES!1800!g" | |
#!substdef "!MSRP_MAX_EXPIRES!3600!g" | |
##!define LOCAL_TEST_RUN | |
###!define WITH_TLS | |
#!define WITH_WEBSOCKETS | |
###!define WITH_MSRP | |
#!define WITH_MYSQL | |
#!define WITH_AUTH | |
#!define WITH_USRLOCDB | |
####### Global Parameters ######### | |
fork=yes | |
children=4 | |
#!ifdef WITH_TLS | |
enable_tls=1 | |
#!endif | |
listen=MY_IP_ADDR | |
#!ifdef WITH_WEBSOCKETS | |
listen=MY_WS_ADDR | |
#!ifdef WITH_TLS | |
listen=MY_WSS_ADDR | |
#!endif | |
#!endif | |
#!ifdef WITH_MSRP | |
listen=MY_MSRP_ADDR | |
#!endif | |
tcp_connection_lifetime=3604 | |
tcp_accept_no_cl=yes | |
tcp_rd_buf_size=16384 | |
syn_branch=0 | |
#!ifdef LOCAL_TEST_RUN | |
debug=2 | |
mpath="modules_k:modules" | |
#!else | |
debug=0 | |
mpath="/opt/kamailio/lib64/kamailio/modules_k/:/opt/kamailio/lib64/kamailio/modules/" | |
#!endif | |
#loadmodule "db_sqlite.so" | |
loadmodule "db_mysql.so" | |
loadmodule "tm.so" | |
loadmodule "sl.so" | |
loadmodule "rr.so" | |
loadmodule "pv.so" | |
loadmodule "maxfwd.so" | |
loadmodule "usrloc.so" | |
loadmodule "registrar.so" | |
loadmodule "textops.so" | |
loadmodule "siputils.so" | |
loadmodule "xlog.so" | |
loadmodule "sanity.so" | |
loadmodule "ctl.so" | |
loadmodule "auth.so" | |
loadmodule "auth_db.so" | |
loadmodule "kex.so" | |
loadmodule "mi_rpc.so" | |
loadmodule "corex.so" | |
#!ifdef WITH_TLS | |
loadmodule "tls.so" | |
#!endif | |
#!ifdef WITH_MSRP | |
loadmodule "msrp.so" | |
loadmodule "htable.so" | |
loadmodule "cfgutils.so" | |
#!endif | |
#!ifdef WITH_WEBSOCKETS | |
loadmodule "xhttp.so" | |
loadmodule "websocket.so" | |
loadmodule "nathelper.so" | |
#!endif | |
# ----------------- setting module-specific parameters --------------- | |
# ----- tm params ----- | |
# auto-discard branches from previous serial forking leg | |
modparam("tm", "failure_reply_mode", 3) | |
# default retransmission timeout: 30sec | |
modparam("tm", "fr_timer", 30000) | |
# default invite retransmission timeout after 1xx: 120sec | |
modparam("tm", "fr_inv_timer", 120000) | |
# ----- 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) | |
# ----- registrar params ----- | |
modparam("registrar", "method_filtering", 1) | |
modparam("registrar", "max_expires", 3600) | |
modparam("registrar", "gruu_enabled", 0) | |
# ----- usrloc params ----- | |
modparam("usrloc", "db_url", "DBURL") | |
modparam("usrloc", "db_mode", 0) | |
# ----- auth params ----- | |
modparam("auth", "nonce_count", 1) | |
modparam("auth", "qop", "auth") | |
# ----- auth_db params ----- | |
modparam("auth_db", "db_url", "DBURL") | |
modparam("auth_db", "calculate_ha1", yes) | |
modparam("auth_db", "password_column", "password") | |
modparam("auth_db", "load_credentials", "id") | |
# ----- corex params ----- | |
modparam("corex", "alias_subdomains", "MY_DOMAIN") | |
#!ifdef WITH_TLS | |
# ----- tls params ----- | |
modparam("tls", "tls_method", "SSLv23") | |
modparam("tls", "certificate", "/etc/pki/CA/ser1_cert.pem") | |
modparam("tls", "private_key", "/etc/pki/CA/privkey.pem") | |
modparam("tls", "ca_list", "/etc/pki/CA/calist.pem") | |
#!endif | |
#!ifdef WITH_WEBSOCKETS | |
# ----- nathelper params ----- | |
modparam("nathelper|registrar", "received_avp", "$avp(RECEIVED)") | |
# Note: leaving NAT pings turned off here as nathelper is _only_ being used for | |
# WebSocket connections. NAT pings are not needed as WebSockets have | |
# their own keep-alives. | |
#!endif | |
#!ifdef WITH_MSRP | |
# ----- htable params ----- | |
modparam("htable", "htable", "msrp=>size=8;autoexpire=MSRP_MAX_EXPIRES;") | |
#!endif | |
####### Routing Logic ######## | |
# Main SIP request routing logic | |
# - processing of any incoming SIP request starts with this route | |
# - note: this is the same as route { ... } | |
request_route { | |
if ((($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT) | |
&& !(proto == WS || proto == WSS)) || $Rp == MY_MSRP_PORT) { | |
xlog("L_WARN", "SIP request received on $Rp\n"); | |
sl_send_reply("403", "Forbidden"); | |
exit; | |
} | |
# per request initial checks | |
route(REQINIT); | |
#!ifdef WITH_WEBSOCKETS | |
if (nat_uac_test(64)) { | |
# Do NAT traversal stuff for requests from a WebSocket | |
# connection - even if it is not behind a NAT! | |
# This won't be needed in the future if Kamailio and the | |
# WebSocket client support Outbound and Path. | |
force_rport(); | |
if (is_method("REGISTER")) { | |
fix_nated_register(); | |
} else { | |
if (!add_contact_alias()) { | |
xlog("L_ERR", "Error aliasing contact <$ct>\n"); | |
sl_send_reply("400", "Bad Request"); | |
exit; | |
} | |
} | |
} | |
#!endif | |
# handle requests within SIP dialogs | |
route(WITHINDLG); | |
### only initial requests (no To tag) | |
# CANCEL processing | |
if (is_method("CANCEL")) { | |
if (t_check_trans()) { | |
t_relay(); | |
} | |
exit; | |
} | |
t_check_trans(); | |
# authentication | |
route(AUTH); | |
# record routing for dialog forming requests (in case they are routed) | |
# - remove preloaded route headers | |
remove_hf("Route"); | |
if (is_method("INVITE")) { | |
record_route(); | |
} | |
# handle registrations | |
route(REGISTRAR); | |
if ($rU==$null) { | |
# request with no Username in RURI | |
sl_send_reply("484", "Address Incomplete"); | |
exit; | |
} | |
# user location service | |
route(LOCATION); | |
route(RELAY); | |
} | |
route[RELAY] { | |
if (!t_relay()) { | |
sl_reply_error(); | |
} | |
exit; | |
} | |
# Per SIP request initial checks | |
route[REQINIT] { | |
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; | |
} | |
if (uri == myself && is_method("OPTIONS") && !(uri=~"sip:.*[@]+.*")) { | |
options_reply(); | |
exit; | |
} | |
} | |
# Handle requests within SIP dialogs | |
route[WITHINDLG] { | |
if (has_totag()) { | |
# sequential request withing a dialog should | |
# take the path determined by record-routing | |
if (loose_route()) { | |
#!ifdef WITH_WEBSOCKETS | |
if ($du == "") { | |
if (!handle_ruri_alias()) { | |
xlog("L_ERR", "Bad alias <$ru>\n"); | |
sl_send_reply("400", "Bad Request"); | |
exit; | |
} | |
} | |
#!endif | |
route(RELAY); | |
} else { | |
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 | |
t_relay(); | |
exit; | |
} else { | |
# ACK without matching transaction... | |
# ignore and discard | |
exit; | |
} | |
} | |
sl_send_reply("404", "Not Found"); | |
} | |
exit; | |
} | |
} | |
# Handle SIP registrations | |
route[REGISTRAR] { | |
if (is_method("REGISTER")) { | |
if (!save("location")) { | |
sl_reply_error(); | |
} | |
exit; | |
} | |
} | |
# USER location service | |
route[LOCATION] { | |
if (!is_subscriber("$ru", "subscriber", "1")) { | |
t_newtran(); | |
send_reply("404", "Not Found"); | |
exit; | |
} | |
if (!lookup("location")) { | |
$var(rc) = $rc; | |
t_newtran(); | |
switch ($var(rc)) { | |
case -1: | |
send_reply("480", "Temporarily Unavailable"); | |
exit; | |
case -2: | |
send_reply("405", "Method Not Allowed"); | |
exit; | |
case -3: | |
send_reply("500", "Server Internal Error"); | |
exit; | |
} | |
} | |
} | |
# Authentication route | |
route[AUTH] { | |
if (is_method("REGISTER") || from_uri==myself) { | |
# authenticate requests | |
if (!auth_check("$fd", "subscriber", "1")) { | |
auth_challenge("$fd", "0"); | |
exit; | |
} | |
# user authenticated - remove auth header | |
if(!is_method("REGISTER")) { | |
consume_credentials(); | |
} | |
} | |
# if caller is not local subscriber, then check if it calls | |
# a local destination, otherwise deny, not an open relay here | |
if (from_uri!=myself && uri!=myself) { | |
sl_send_reply("403", "Forbidden"); | |
exit; | |
} | |
} | |
#!ifdef WITH_WEBSOCKETS | |
onreply_route { | |
if ((($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT) | |
&& !(proto == WS || proto == WSS)) || $Rp == MY_MSRP_PORT) { | |
xlog("L_WARN", "SIP response received on $Rp\n"); | |
drop; | |
exit; | |
} | |
if (nat_uac_test(64)) { | |
# Do NAT traversal stuff for replies to a WebSocket connection | |
# - even if it is not behind a NAT! | |
# This won't be needed in the future if Kamailio and the | |
# WebSocket client support Outbound and Path. | |
add_contact_alias(); | |
} | |
} | |
event_route[xhttp:request] { | |
set_reply_close(); | |
set_reply_no_connect(); | |
if ($Rp != MY_WS_PORT | |
#!ifdef WITH_TLS | |
&& $Rp != MY_WSS_PORT | |
#!endif | |
) { | |
xlog("L_WARN", "HTTP request received on $Rp\n"); | |
xhttp_reply("403", "Forbidden", "", ""); | |
exit; | |
} | |
xlog("L_DBG", "HTTP Request Received\n"); | |
if ($hdr(Upgrade)=~"websocket" | |
&& $hdr(Connection)=~"Upgrade" | |
&& $rm=~"GET") { | |
# Validate Host - make sure the client is using the correct | |
# alias for WebSockets | |
if ($hdr(Host) == $null || !is_myself("sip:" + $hdr(Host))) { | |
xlog("L_WARN", "Bad host $hdr(Host)\n"); | |
xhttp_reply("403", "Forbidden", "", ""); | |
exit; | |
} | |
# Optional... validate Origin - make sure the client is from an | |
# authorised website. For example, | |
# | |
# if ($hdr(Origin) != "http://communicator.MY_DOMAIN" | |
# && $hdr(Origin) != "https://communicator.MY_DOMAIN") { | |
# xlog("L_WARN", "Unauthorised client $hdr(Origin)\n"); | |
# xhttp_reply("403", "Forbidden", "", ""); | |
# exit; | |
# } | |
# Optional... perform HTTP authentication | |
# ws_handle_handshake() exits (no further configuration file | |
# processing of the request) when complete. | |
if (ws_handle_handshake()) | |
{ | |
# Optional... cache some information about the | |
# successful connection | |
exit; | |
} | |
} | |
xhttp_reply("404", "Not Found", "", ""); | |
} | |
event_route[websocket:closed] { | |
xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n"); | |
} | |
#!endif | |
#!ifdef WITH_MSRP | |
event_route[msrp:frame-in] { | |
msrp_reply_flags("1"); | |
if ((($Rp == MY_WS_PORT || $Rp == MY_WSS_PORT) | |
&& !(proto == WS || proto == WSS)) && $Rp != MY_MSRP_PORT) { | |
xlog("L_WARN", "MSRP request received on $Rp\n"); | |
msrp_reply("403", "Action-not-allowed"); | |
exit; | |
} | |
if (msrp_is_reply()) { | |
msrp_relay(); | |
} else if($msrp(method)=="AUTH") { | |
if($msrp(nexthops)>0) { | |
msrp_relay(); | |
exit; | |
} | |
if (!www_authenticate("MY_DOMAIN", "subscriber", | |
"$msrp(method)")) { | |
if (auth_get_www_authenticate("MY_DOMAIN", "1", | |
"$var(wauth)")) { | |
msrp_reply("401", "Unauthorized", | |
"$var(wauth)"); | |
} else { | |
msrp_reply("500", "Server Error"); | |
} | |
exit; | |
} | |
if ($hdr(Expires) != $null) { | |
$var(expires) = (int) $hdr(Expires); | |
if ($var(expires) < MSRP_MIN_EXPIRES) { | |
msrp_reply("423", "Interval Out-of-Bounds", | |
"Min-Expires: MSRP_MIN_EXPIRES\r\n"); | |
exit; | |
} else if ($var(expires) > MSRP_MAX_EXPIRES) { | |
msrp_reply("423", "Interval Out-of-Bounds", | |
"Max-Expires: MSRP_MAX_EXPIRES\r\n"); | |
exit; | |
} | |
} else { | |
$var(expires) = MSRP_MAX_EXPIRES; | |
} | |
$var(cnt) = $var(cnt) + 1; | |
pv_printf("$var(sessid)", "s.$(pp).$(var(cnt)).$(RANDOM)"); | |
$sht(msrp=>$var(sessid)::srcaddr) = $msrp(srcaddr); | |
$sht(msrp=>$var(sessid)::srcsock) = $msrp(srcsock); | |
$shtex(msrp=>$var(sessid)) = $var(expires) + 5; | |
# - Use-Path: the MSRP address for server + session id | |
$var(hdrs) = "Use-Path: msrps://MY_IP_ADDR:MY_MSRP_PORT/" | |
+ $var(sessid) + ";tcp\r\n" | |
+ "Expires: " + $var(expires) + "\r\n"; | |
msrp_reply("200", "OK", "$var(hdrs)"); | |
} else if ($msrp(method)=="SEND" || $msrp(method)=="REPORT") { | |
if ($msrp(nexthops)>1) { | |
if ($msrp(method)!="REPORT") { | |
msrp_reply("200", "OK"); | |
} | |
msrp_relay(); | |
exit; | |
} | |
$var(sessid) = $msrp(sessid); | |
if ($sht(msrp=>$var(sessid)::srcaddr) == $null) { | |
# one more hop, but we don't have address in htable | |
msrp_reply("481", "Session-does-not-exist"); | |
exit; | |
} else if ($msrp(method)!="REPORT") { | |
msrp_reply("200", "OK"); | |
} | |
msrp_relay_flags("1"); | |
msrp_set_dst("$sht(msrp=>$var(sessid)::srcaddr)", | |
"$sht(msrp=>$var(sessid)::srcsock)"); | |
msrp_relay(); | |
} else { | |
msrp_reply("501", "Request-method-not-understood"); | |
} | |
} | |
#!endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment